System.ComponentModel.Win32Exception: "Ошибка создания дескриптора окна."

Моя проблема:

System.ComponentModel.Win32Exception: "Ошибка создания дескриптора окна".

Я знаю, что могу решить эту проблему с Dispose(), но когда я использую его в программе, я отображаю другую ошибку:

System.ObjectDisposedException: 'Невозможно получить доступ к удаленному объекту. Имя объекта: "PictureBox". '

Я использую следующий код:

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]);
        }
    }
}

Когда я хочу создать 10000 объектов

Эта ошибка отображается.

3 ответа

Решение

Моя проблема:

System.ComponentModel.Win32Exception: "Ошибка создания дескриптора окна".

В самом деле. Вы создаете слишком много элементов управления для Winforms приложение.

И избавление от них не очень помогает, потому что вы больше не можете использовать выбрасываемый объект.

Чтобы иметь такую ​​большую головоломку (10 тыс. Штук), вам нужно отказаться от использования PictureBoxes (или любой другой Controls), чтобы показать кусочки головоломки для другого подхода. Это было предложено в первоначальном вопросе, но тогда вы хотели иметь только 100 штук, помните?

Наиболее распространенный подход заключается в следующем: ведите список изображений (когда они <= 256x256 пикселей, поместите их в ImageList!) и нарисуйте их на доске Paint событие. Это избавит от всех накладных расходов, связанных с PictureBoxes,

(В сторону: можно подумать, что это не будет производительным со всеми DrawImage звонки. Но все те PictureBoxes Также необходимо нарисовать все пиксели на всех их поверхностях, так что это не проблема. Но они также должны нести накладные расходы, будучи (под капотом) полностью функциональными windows (см. сообщение об ошибке!), поэтому в системе их может быть только ограниченное количество; всегда старайтесь сохранить количество элементов управления <1k!)

Вы должны будете переместить логику размещения на доску Paint событие, а также придется изменить модель события..:

Вместо того, чтобы каждый PictureBox Отвечая на собственные события, вам нужно будет найти способ выполнить всю работу на мероприятиях форума. Это должно быть различным, в зависимости от события.

Поскольку мы не знаем, какое у вас мероприятие и что они делают, и какие данные им нужны для их работы, сложно дать все необходимые детали, поэтому я просто укажу несколько вещей:

  • Там не будет Enter или же Leave событие, которое вы можете использовать. Вместо этого вам нужно обнаружить вход в область фигуры, проверив ее в событии MouseMove. Если вы держите List<Rectangle> ты можешь использовать Rectangle.Contains(e.Location) для этого теста.

  • Вы можете обнаружить MouseClick, но затем вам нужно будет выяснить, в какой области щелкнули. Если ваша логика Enter и Leave из MouseMove работает, вы можете использовать ее результат, чтобы узнать, куда прошел Click.

Подобные идеи могут быть использованы для всех других событий; некоторые из них простые, некоторые требуют небольшого расчета, но все они будут быстрыми и довольно простыми в реализации.

Чтобы оптимизировать производительность, попробуйте сделать изображение нужного размера и использовать Format32bppPArgb в качестве формата пикселей, потому что оно быстрее отображается.

Другой вариант - извлечь данные пикселей прямо из исходного изображения в Paint событие с теми же вычислениями, которые вы используете сейчас, чтобы создать их. (E сть DrawImage наложение, которое использует два Rectanglesодин для определения цели и один для области источника..) Это сохраняет GDI ручки, по крайней мере, если вы не можете использовать ImageList,

Всегда планируйте рост! Для лучшей реализации создайте Piece учебный класс. Это должно держать Rectangle и целочисленный индекс в ImageList"s Images коллекция. Это также может иметь метод Switch(Piece otherPiece) который либо переключит Rectangles или индексы.

Удачи:-)

Я встретил это исключение, потому что бесконечный цикл создает новый элемент управления UI и устанавливает его свойства. После многократного зацикливания это исключение выдается при изменении видимого свойства элемента управления. Я обнаружил, что и пользовательский объект, и объект GDI (из диспетчера задач) довольно большие.

Я полагаю, что ваша проблема - та же причина, по которой системные ресурсы истощаются этими элементами управления пользовательским интерфейсом.

Я комментирую 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);
        }
Другие вопросы по тегам