【问题标题】:System.ComponentModel.Win32Exception: 'Error creating window handle.'System.ComponentModel.Win32Exception:“创建窗口句柄时出错。”
【发布时间】:2018-09-04 07:20:54
【问题描述】:

我的问题是:

System.ComponentModel.Win32Exception: '创建窗口句柄时出错'。

我知道我可以用Dispose() 解决这个问题,但是当我在程序中使用它时,我显示另一个错误:

System.ObjectDisposedException: '无法访问已处置的对象。 对象名称:“图片框”。 '

我使用以下代码:

private void SetUpPuzzle_Click(int parts)
{
    Panel P = new Panel
    {
        Size = new Size(200, 200),
        Location = new Point(394, 62),
    };

    Controls.Add(P);
    Control board = P;
    int total = parts * parts;
    var PB = new PictureBox[total];
    var imgarray = new Image[total];
    var img = User_Image.Image;
    int W = img.Width / (int.Parse(Math.Sqrt(double.Parse(parts.ToString())).ToString()));
    int H = img.Height / (int.Parse(Math.Sqrt(double.Parse(parts.ToString())).ToString()));
    int size = 200 / (int.Parse(Math.Sqrt(double.Parse(parts.ToString())).ToString()));

    for (int x = 0; x < parts; x++)
    {
        for (int y = 0; y < parts; y++)
        {
            var index = x * parts + y;

            imgarray[index] = new Bitmap(W, H);
            using (Graphics graphics = Graphics.FromImage(imgarray[index]))
                graphics.DrawImage(img, new Rectangle(0, 0, W, H),
                                   new Rectangle(x * W, y * H, W, H), GraphicsUnit.Pixel);

            PB[index] = new PictureBox
            {
                Name = "P" + index,
                Size = new Size(size, size),
                Location = new Point(x * size, y * size),
                Image = imgarray[index],
                SizeMode = PictureBoxSizeMode.StretchImage
            };

            PB[index].MouseEnter += Images_M_E;
            PB[index].MouseLeave += Images_M_L;
            PB[index].MouseClick += Form_MouseClick;
            *PB[index].Dispose();
            *board.Controls.Add(PB[index]);
        }
    }
}

当我想创建 10,000 个对象时

显示此错误。

【问题讨论】:

  • 如果你包含这些被抛出的行会很有帮助
  • 我不明白你的意思
  • 哪一行出错了?
  • 在标有 * 的行中。
  • 请替换我的代码并测试。

标签: c# dispose objectdisposedexception win32exception


【解决方案1】:

我的问题是:

System.ComponentModel.Win32Exception: '创建窗口句柄时出错'。

的确如此。您正在为Winforms 应用程序创建太多控件

并且处置它们并没有真正的帮助,因为您不能再使用已处置的对象..

要制作这种大型拼图(10k 块),您需要从使用PictureBoxes(或任何其他Controls)来显示拼图块更改为不同的方法。 original question 中已建议这样做,但您只想拥有 100 件,记得吗?

最常见的方法是:保留图像列表(当它们 ImageList!)并在板的Paint 事件中绘制它们。这将消除与PictureBoxes 相关的所有开销。

(旁白:人们可能认为这不会对所有DrawImage 调用都有效。但是所有PictureBoxes 还需要在其所有表面上绘制所有像素,所以这没有问题。但他们也有承担(在引擎盖下)全功能windows 的开销(请参阅错误消息!),这就是系统只能拥有有限数量的原因;始终尝试保持控件的数量!)

您必须将放置逻辑移至看板的Paint 事件,并且还必须更改事件模型..:

不是让每个PictureBox 响应自己的事件,您将不得不找到一种方法来完成董事会事件中的所有工作。这必须有所不同,具体取决于事件。

由于我们不知道您举办了哪些活动,他们做了什么以及他们的工作需要哪些数据,所以很难提供所有必要的细节,所以我只指出一些事情..:

  • 不会有您可以使用的EnterLeave 事件。相反,您需要通过在 MouseMove 事件中对其进行测试来检测进入一块区域。如果您保留List&lt;Rectangle&gt;,则可以使用Rectangle.Contains(e.Location) 进行此测试。

  • 您可以检测到鼠标单击,但随后必须找出单击了哪个区域。如果 MouseMove 中的 Enter 和 Leave 逻辑正常工作,您可以使用其结果来了解 Click 的位置。

类似的想法可用于所有其他事件;有些很简单,有些需要一点计算,但它们都很快而且很容易实现..

为了优化性能,请尝试使图像 n 大小合适,并使用Format32bppPArgb 作为像素格式,因为这样显示起来会更快。

另一种选择是直接从 Paint 事件中的原始图像中提取像素数据,使用您现在用来创建它们的相同计算。 (有一个DrawImage 覆盖使用两个Rectangles,一个用于确定目标,一个用于源区域。)这可以节省GDI 句柄,至少如果您不能使用ImageList

始终为增长做计划!为了更好的实现,请创建一个Piece 类。它应该包含RectangleImageListImages 集合的整数索引。它还可以有一个方法Switch(Piece otherPiece),可以切换Rectangles 或索引。

祝你好运:-)

【讨论】:

  • 感谢您的回答。最好的尊重
【解决方案2】:

我遇到了这个异常,因为无限循环创建了新的 UI 控件并设置了它的属性。循环多次后,更改控件可见属性时抛出此异常。我发现用户对象和 GDI 对象(来自任务管理器)都很大。

我猜您的问题与这些 UI 控件耗尽系统资源的原因类似。

【讨论】:

    【解决方案3】:

    我评论PB[index].Dispose();,它的工作。

    private void SetUpPuzzle(int parts)
            {
                // Comment ***********
                //Panel P = new Panel
                //{
                //    Size = new Size(200, 200),
                //    Location = new Point(394, 62),
                //};
    
                //Controls.Add(P);
                //Control board = P;     ***********
                int total = parts * parts;
                var PB = new PictureBox[total];
                var imgarray = new Image[total];
                var img = User_Image.Image;
                int W =Convert.ToInt32(img.Width / Math.Sqrt(parts));
                int H = Convert.ToInt32(img.Height / Math.Sqrt(parts));
                int size = Convert.ToInt32(200 / Math.Sqrt(parts));
    
                for (int x = 0; x < parts; x++)
                {
                    for (int y = 0; y < parts; y++)
                    {
                        var index = x * parts + y;
    
                        imgarray[index] = new Bitmap(W, H);
                        using (Graphics graphics = Graphics.FromImage(imgarray[index]))
                            graphics.DrawImage(img, new Rectangle(0, 0, W, H),
                                               new Rectangle(x * W, y * H, W, H), GraphicsUnit.Pixel);
    
                        PB[index] = new PictureBox
                        {
                            Name = "P" + index,
                            Size = new Size(size, size),
                            Location = new Point(x * size, y * size),
                            Image = imgarray[index],
                            SizeMode = PictureBoxSizeMode.StretchImage
                        };
    
                        PB[index].MouseEnter += Form1_MouseEnter; 
                        PB[index].MouseLeave += Form1_MouseLeave; 
                        PB[index].MouseClick += Form1_MouseClick; 
                        //Comment                         
                        //PB[index].Dispose();       < -----------------
                        // Add PB in Panel in form
                        panel1.Controls.Add(PB[index]);
    
    
                    }
                }
                // after add all refresh panel
                panel1.Refresh();
            }
    
    
            private void Form1_MouseClick(object sender, MouseEventArgs e)
            {
                throw new NotImplementedException();
            }
    
            private void Form1_MouseLeave(object sender, EventArgs e)
            {
                throw new NotImplementedException();
            }
    
            private void Form1_MouseEnter(object sender, EventArgs e)
            {
                throw new NotImplementedException();
            }
    

    然后在您的按钮中调用SetUpPuzzle 方法,例如:

    private void button1_Click(object sender, EventArgs e)
            {
                SetUpPuzzle(10);
            }
    

    【讨论】:

    • 当我要创建 10,000 个对象时显示此错误。
    • 我10000以下没有问题
    • @آرمانغروی 所以您想在 UI 上创建超过 10,000 个控件?然后我猜你可能用完了资源/可用的句柄。您是否考虑过使用某种 UI 虚拟化?
    • 您的代码无效。 System.ComponentModel.Win32Exception: '创建窗口句柄时出错。'
    猜你喜欢
    • 2011-10-17
    • 1970-01-01
    • 2013-01-30
    • 2013-06-02
    • 2017-09-25
    • 2016-09-01
    • 2013-12-10
    相关资源
    最近更新 更多