我的程序是CRM,我使用了Rad Ribbon Bar,因此使用了许多带有图像的按钮,RadGridView(其中一些列包含图像)以及许多其他包含图像的控件。这是一个MDI父/子程序。

c# - System.Drawing Main()方法上的内存不足异常-C#-LMLPHP

在许多情况下,加载mdi子项或使用某些网格 View 时,程序将挂起并给出此错误:

OutOfMemoryException occurred in System.Drawing.dll

我在某些部分上尝试了GC.Collect(),但没有成功。设置图像没有代码!例如,为按钮设置图像时,我在Visual Studio中使用了其属性。我已在可视模式下使用属性面板以这种方式设置了所有其他控件图像。

c# - System.Drawing Main()方法上的内存不足异常-C#-LMLPHP

这些是与绘图相关的一些设计师代码:
    btnCustomerList.Image = global::MyApp.Properties.Resources.CustomerList32;

    gridViewCommandColumn1.Image = global::MyApp.Properties.Resources.ViewShop32;

当在使用应用程序一段时间后出现错误时,它将显示在Program.csApplication.Run(new MainForm());行中:
    static void Main()
    {
        AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", AppDomain.CurrentDomain.BaseDirectory + "\\Settings.config");
        bool ok;
        Mutex m = new Mutex(true, WindowsIdentity.GetCurrent().Name.ToString().Split('\\')[1] + "MyApp", out  ok);
        if (ok)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            // The Error will cause HERE
            Application.Run(new MainForm());

            GC.KeepAlive(m);
        }
        else
            Application.Exit();
    }
MainForm是包含功能区栏的mdi父级。
这是完整堆栈跟踪:
at System.Drawing.Image.FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
at System.Drawing.Image.FromHbitmap(IntPtr hbitmap)
at System.Drawing.Icon.ToBitmap()
at System.Windows.Forms.ThreadExceptionDialog..ctor(Exception t)
at System.Windows.Forms.Application.ThreadContext.OnThreadException(Exception t)
at System.Windows.Forms.Control.WndProcException(Exception e)
at System.Windows.Forms.Control.ControlNativeWindow.OnThreadException(Exception e)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at MyApp.Program.Main() in d:\\MyApp\\Application\\MyApp\\Program.cs:line 36"

已更新:

通过单击功能区栏按钮调用mdi-children的代码在此处:
private void btnCustomerList_Click(object sender, EventArgs e)
{
    OpenForm(new FormCustomerList(), "Customer List");
}

private void btnCustomerRelated_Click(object sender, EventArgs e)
{
    OpenForm(new FormCustomerRelated(), "Customer Related");
}

这是OpenForm方法:
private void OpenForm(Form formType, string Caption)
{
    foreach (Form nform in Application.OpenForms)
    {
        if (nform.GetType() == formType.GetType())
        {
            nform.Activate();
            return;
        }
    }
    this.MdiChildren.OfType<Form>().ToList().ForEach(x => x.Dispose());
    GC.Collect();

    Form form = formType;
    form.MdiParent = this;
    form.Dock = DockStyle.Fill;
    form.Show();
    this.Text = Caption;
}

在每个mdi child 的表单构造函数中,在InitializeComponent();之后,我也写了GC.Collect();。但是正如评论中所述,任务管理器中的GDI objects将不断增加,直到10000对象,然后应用程序将崩溃。

更新:最重要的问题

看来我找到了导致GDI objects最多的部分。在每种形式中都有一些控件,例如文本框,下拉列表等。我为它们设置了一些规则,例如,如果用户输入文本框,则其底色应为黄色,离开后应再次为白色。因此,有一个主要方法,我以表格加载的形式调用该方法,以遍历所有控件并找到目标控件,并使用定义的规则添加例如enter和离开事件。像这样的东西:
private void FormCustomerList_Load(object sender, EventArgs e)
{
    ClassCRMControls.AddEventHandler(this);
}

并在ClassCRMControls类中:
public static void AddEventHandler(Control parent)
{
    foreach (Control c in parent.Controls)
    {
        if (c.GetType() == typeof(RadTextBox))
        {
            c.Enter += new EventHandler(ClassCRMControls.EnterEvent);
            c.Leave += new EventHandler(ClassCRMControls.LeaveEvent);
        }
        else
            AddEventHandler(c);
    }
}

private static void EnterEvent(object sender, EventArgs e)
{
    (sender as RadTextBox).TextBoxElement.TextBoxItem.BackColor = Color.FromArgb(255, 251, 147);
}

private static void LeaveEvent(object sender, EventArgs e)
{
      (sender as RadTextBox).TextBoxElement.TextBoxItem.ResetValue(LightVisualElement.BackColorProperty, ValueResetFlags.Local);
}

最佳答案

我已经找到问题的根源,这也是我用于网格和其他控件的自定义动画光标。我像这样初始化它:

this.Cursor = ClassObjects.CreateAnimatedCursor("C:\\aniCur.ani"));

由于每次以任何方式使用它都会从文件中加载该光标,因此创建了越来越多的GDI Objects

所以我这样声明了public static cursor各自形式的main():
public static Cursor animCur = ClassObjects.CreateAnimatedCursor("C:\\aniCur.ani"));

然后每当我需要使用此游标时,我只需从表单中引用该对象public static cursor
this.Cursor = MainForm.animCur;

而已 :)

我怎么找到的?我只是尝试删除(注释)一些我怀疑它们的代码,然后在任务管理器中检查了GDI objects。经过一些测试后,很明显新的光标对象的不断加载导致了问题。

关于c# - System.Drawing Main()方法上的内存不足异常-C#,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47069165/

10-13 03:48