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