System.ComponentModel.Win32Exception: «Ошибка создания дескриптора окна.» - PullRequest
0 голосов
/ 04 сентября 2018

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

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

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

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

Ответы [ 3 ]

0 голосов
/ 05 сентября 2018

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Удачи: -)

0 голосов
/ 17 сентября 2018

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

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

0 голосов
/ 04 сентября 2018

Я комментирую 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);
        }
...