各位老大,我现在有个form程序,功能是餐饮点菜前台,页面上现实当前在用的餐桌,因为餐桌是不确定的,所以需要动态添加,我是在panel里动态添加子控件的,代码片段如下:private void initDesk()
        {
            string strSql = dkSql;
            if (strSql == "") return;
            if (dtDk == null)
            {
                dtDk = bm.GetUserAllDesk(strSql); //获得子控件个数
            }
            
            this.pnlDesk.Controls.Clear();//添加前先清空            if (dtDk.Rows.Count > 0)
            {
                // 分页片段==============================
                if (dtDk.Rows.Count % dkPageSize == 0)
                {
                    dkPageCount = dtDk.Rows.Count / dkPageSize;
                }
                else
                {
                    dkPageCount = dtDk.Rows.Count / dkPageSize + 1;
                }
                int start = (dkPageIndex - 1) * dkPageSize;
                int end = start + dkPageSize - 1;
                if (end > dtDk.Rows.Count - 1) end = dtDk.Rows.Count - 1;
                // 分页片段==============================                int cols = 9;//列数
                int iLine = 0;//行数
                int sum = end - start; //当前页需要显示数目                if ((sum + 1) % cols == 0)
                {
                    iLine = (sum+1) / cols;
                }
                else
                {
                    iLine = (sum + 1) / cols + 1;
                }                //动态添加按钮                                    int i = 0;
                int j = 0;
                int s = start;
                DeskControl btn;//自定义子控件
                while (j < iLine)
                {
                    btn = new DeskControl();//初始化
                    btn.Location = new System.Drawing.Point(100 * i +10*i + 20, 10 * j + 100*j + 3);//显示位置
                   
                    btn.Size = new System.Drawing.Size(100, 100);//显示大小
                    btn.Name = dtDk.Rows[s]["dkID"].ToString();//名称
                    btn.DcDeskNum.Text = dtDk.Rows[s]["dkName"].ToString();
                    
                    string isbusy = dtDk.Rows[s]["dkIsBusy"].ToString();
                    if (isbusy.ToLower() == "false")
                    {
                        // 这些都是子控件里一些属性和方法赋值,下同
                        btn.setEmpty();
                        btn.DcMoney.Visible = false;
                        btn.DcTime.Visible = false;
                        btn.DcPersonCount.Text = dtDk.Rows[s]["dktPrnCountLow"].ToString() + "-" + dtDk.Rows[s]["dktPrnCountHigh"].ToString();
                    }
                    else if (isbusy.ToLower() == "true")
                    {
                        btn.setBusy();
                        try
                        {
                            btn.DcMoney.Text = ((Decimal)dtDk.Rows[s]["slValue"]).ToString("f2");
                            btn.DcTime.Text = ((DateTime)dtDk.Rows[s]["slStartTime"]).ToString("HH:mm");
                            btn.DcPersonCount.Text = dtDk.Rows[s]["slPersonCount"].ToString();
                        }
                        catch{ }
                        
                    }
                    else
                    {
                        btn.setEmpty();
                        btn.DcMoney.Visible = false;
                        btn.DcTime.Visible = false;
                        btn.DcPersonCount.Visible = false;
                    }
                    btn.ControlClik += new DeskControl.ControlClickEventHandler(Desk_Click);//子控件点击事件
                    this.pnlDesk.Controls.Add(btn);//添加子控件
                    
                    // 以下控制换行
                    i++;
                    s++;
                    if (i > cols - 1)
                    {
                        i = 0;
                        j++;
                    }
                    if (s > end)
                    {
                        break;
                    }
                }
                
            }
        }
程序运行没有问题,但是initDesk()方法会被重复调用,就是说会一直反复清空子控件再添加子控件,系统运行20分钟后就出错了,如下:
应用程序出错:System.ComponentModel.Win32Exception: Error creating window handle.
   at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)
   at System.Windows.Forms.Control.CreateHandle()
   at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   at System.Windows.Forms.Control.CreateControl()
   at System.Windows.Forms.Control.ControlCollection.Add(Control value)
   at Restaurant.FrmMainDesk.initDesk()
   at Restaurant.FrmMainDesk.btnDkNext_Click(Object sender, EventArgs e)
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at Restaurant.Common.BitmapButton.OnMouseUp(MouseEventArgs e)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
错误描述:Application_ThreadExceptionError creating window handle是系统报错,似乎在注册表里有个阀值限制,但是我必须是动态添加控件,是否有什么好的方法。这个错误报错的位置不确定,反正每次都是报:Error creating window handle。各位老大帮帮忙啊!动态添加子控件 控件

解决方案 »

  1.   

    http://blog.sina.com.cn/s/blog_5f9714fe0100sexc.html
      

  2.   

    你好像每次都是重新取数据然后重绘界面,
    不管你是重绘还是重新填充子控,似乎都应该只处理发生变化的那部分?
    重绘可以(Invalidate指定区域),不过会涉及到一些几何换算
    换成子控件逻辑上更容易把控,性能方面,同一时刻改变的桌位应该也不会太多
      

  3.   

     DeskControl btn;//自定义子控件
    这一句应该放进while循环里,因为你每一个桌位都是一个对象,而你现在的逻辑是只有一个对象,当你添加一个桌位,再添加另一个桌位的时候,因为是对象,都在跟着变化
      

  4.   

    哦,我看错了,你在while里面new了
      

  5.   

    因为每次操作,都可能导致容器里的控件是变化的,控件个数、控件属性,所以操作后先清空容器,然后重新添加一次控件集合!感觉是哪里资源占用了太多handle,难道是没有释放!运行20分钟-1个小时后一般就报错了!
      

  6.   

    控件变化相对总数来说是很小的一部分,所以,你找出这一部分再处理就行了
    另外,在批量操作时
    this.pnlDesk.SuspendLayout();
    initDesk();
    this.pnlDesk.ResumeLayout();
      

  7.   

    1.类似你这样的需求,本不应该使用控件的。底层维护一整个餐桌对象集合信息,其余界面显示全部自己使用GDI绘制而成,数据跟显示分离开来,既不会出现以上问题,也能提高效率。2.一个windows应用程序所使用的任何句柄(一种资源)都是有限的,按照楼主描述,肯定是Handle没有释放完全,造成资源匮乏,打开任务管理器,选择“查看”菜单,选择“选择列...”,选中“句柄数”、“用户对象”、“GDI对象”,如下图:
    然后运行程序,观察数值变化如果能看见这些数值一直增大,说明程序的确存在泄露资源问题,那么你可以:
    1)确保每次清空COntrols之后,每个子控件都dispose
    2)检查每个子控件,是否注册过其他对象的事件,如果是,请在每个子控件的Dispose(bool disposing)方法中将事件注销。参见 http://www.cnblogs.com/xiaozhi_5638/archive/2013/01/14/2859807.html  关于“弱委托”。
    3)出现这个问题不叫“内存泄露”
      

  8.   

    严重建议:如果熟悉GDI绘图,对于这个需求,不要使用自定义控件,所有的餐桌都可以在Panel的OnPaint中利用GDI绘制完成,你完全可以自己实现一个类似ListView控件出来,任何项(餐桌)的鼠标、键盘事件都可以通过Panel的鼠标、键盘事件转换得到。