none
求高手帮我看看这个winform报错信息 RRS feed

  • 问题

  • 我有一个winform窗口,在显示少量数据的时候完全正常,但显示大量数据(四五千条记录左右)就出现问题,说程序遇到问题需要关闭,由此给你带来不便表示抱歉。我通过调试获取了报错的详细信息,现贴出来求高手帮我看看及解悉一下,有什么解决办法。谢谢。

    ---------------------------------报错信息-------------------------------
    未处理 System.ComponentModel.Win32Exception
      Message="创建窗口句柄时出错。"
      Source="System.Windows.Forms"
      ErrorCode=-2147467259
      NativeErrorCode=1158
      StackTrace:
          在 System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)
          在 System.Windows.Forms.Control.CreateHandle()
          在 System.Windows.Forms.Control.get_Handle()
          在 System.Windows.Forms.Control.CreateGraphicsInternal()
          在 System.Windows.Forms.ThreadExceptionDialog..ctor(Exception t)
          在 System.Windows.Forms.Application.ThreadContext.OnThreadException(Exception t)
          在 System.Windows.Forms.Control.WndProcException(Exception e)
          在 System.Windows.Forms.Control.ControlNativeWindow.OnThreadException(Exception e)
          在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
          在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
          在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
          在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
          在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
          在 System.Windows.Forms.Application.Run(Form mainForm)
      InnerException:
    2010年1月10日 9:15

答案

  • 你的确是每条记录都新建了一个控件,而用户句柄数量是有限的,所以导致了这个问题!我记得默认值的上限是10000,可以通过USERProcessHandleQuota这个注册表项来修改,最大可以设置成18000,最小可以设置成200!
    你的设计不是很合理,建议直接使用DataGridView来显示数据!
    周雪峰
    • 已建议为答案 mazhou 2010年1月11日 10:32
    • 已标记为答案 mldarkModerator 2010年1月13日 14:14
    2010年1月10日 13:35
    版主
  • 每个用户控件是一个活着多个句柄的集合,因此创建过多的用户控件会造成系统分配给每个进程的打开句柄数上限,因此报出 Win32Exception。

    利用自定义 ListView,或者 DataGridView 都可以减少达到上限的概率,从而解决问题。
    Mark Zhou
    2010年1月11日 10:32

全部回复

  • 你好!
         你的代码中调用了非托管代码了吗?如果方便的话,最好提供一下相关的代码啊!
    周雪峰
    2010年1月10日 9:33
    版主
  • 你好,我应该没有调用到非托管的代码啊。我主要是将一些帐务的明细记录显示出来并供编辑。下面是我加载窗口时显示这些明细项的代码:

            //显示单据明细项列表,供查看及编辑。类型BillDetails是明细项实体
            private void ShowTextBoxList(List<BillDetails> bdList)
            {
                panBillTextBox.Controls.Clear();//panBillTextBox是窗体上的Panel
                if (bdList.Count > 0)
                {
                    lbEmpty.Visible = false;  //隐藏无数据时的提示Label
                    Point point = new Point(0, 0);
                    for (int i = 0; i < bdList.Count; i++)
                    {
                        BillDetails bd = bdList[i];
                        //BillDetailsTextBox是一个用户控件,用于把一个明细项显示出来
                                                   BillDetailsTextBox bdtb = new BillDetailsTextBox(bd.ProName, bd.PayMoney, bd.Qty, bd.Unit, bd.Remark);
                        bdtb.Location = point;
                        bdtb.OnPayMoneyChange += new BillDetailsTextBox.PayMoneyChangeHandle(bdtb_OnPayMoneyChange);
                        panBillTextBox.Controls.Add(bdtb);
                        //以下用于控制将各明细项在窗口分三列显示
                                                    if ((i + 1) % 3 == 0)
                        {
                            point.X = 0;
                            point.Y = point.Y + bdtb.Height + rowSpan;
                        }
                        else
                        {
                            point.X = point.X + colSpan + bdtb.Width;
                            if (i == bdList.Count - 1)
                                point.Y = point.Y + bdtb.Height + rowSpan;//最后总长度一定要加上,否则不能显示最后一行。
                                                     }
                    }
                    this.Height = point.Y;
                }
                else
                {
                    //如果无数据,显示无数据时的提示Label
                    lbEmpty.Visible = true;
                }
            }
    2010年1月10日 10:29
  • 请问是哪行抛出的异常?
    周雪峰
    2010年1月10日 10:52
    版主
  • 没有具体的哪一行出错,显示一千几百条记录是正常的,多了就不行。
    2010年1月10日 11:19
  • 有人说是窗口句柄用尽了的原因,因为每条记录New了一个控件。但用DataGridView显示10000+条记录也不会有点题,是不是有什么办法可以解决这个问题的呢?
    2010年1月10日 11:47
  • 你的确是每条记录都新建了一个控件,而用户句柄数量是有限的,所以导致了这个问题!我记得默认值的上限是10000,可以通过USERProcessHandleQuota这个注册表项来修改,最大可以设置成18000,最小可以设置成200!
    你的设计不是很合理,建议直接使用DataGridView来显示数据!
    周雪峰
    • 已建议为答案 mazhou 2010年1月11日 10:32
    • 已标记为答案 mldarkModerator 2010年1月13日 14:14
    2010年1月10日 13:35
    版主
  • 每个用户控件是一个活着多个句柄的集合,因此创建过多的用户控件会造成系统分配给每个进程的打开句柄数上限,因此报出 Win32Exception。

    利用自定义 ListView,或者 DataGridView 都可以减少达到上限的概率,从而解决问题。
    Mark Zhou
    2010年1月11日 10:32