C# 数百个自定义用户控件创建数千个用户对象
我正在创建一个仪表板应用程序,它在C# 数百个自定义用户控件创建数千个用户对象,c#,.net,winforms,user-controls,resource-leak,C#,.net,Winforms,User Controls,Resource Leak,我正在创建一个仪表板应用程序,它在FlowLayoutPanel上显示数百个“项目” 每个“项”都是一个UserControl,由12个文本框或标签组成 我的应用程序查询数据库,然后为每条记录创建一个“项”实例,在将数据添加到FlowLayoutPanel之前,用数据填充标签和文本框 在向面板添加了大约560个项目后,我注意到我的任务管理器中的用户对象计数增加到了大约7300个,这比我机器上的任何其他应用都要大得多 我估计560*13(12个标签加上UserControl本身)是7280。所以突
FlowLayoutPanel
上显示数百个“项目”
每个“项”都是一个UserControl
,由12个文本框或标签组成
我的应用程序查询数据库,然后为每条记录创建一个“项”实例,在将数据添加到FlowLayoutPanel
之前,用数据填充标签和文本框
在向面板添加了大约560个项目后,我注意到我的任务管理器中的用户对象
计数增加到了大约7300个,这比我机器上的任何其他应用都要大得多
我估计560*13(12个标签加上UserControl本身)是7280。所以突然泄露了所有物体的来源
知道在windows放弃之前有10000个用户对象的限制,我正试图找到更好的方法将这些“项”绘制到FlowLayoutPanel
上
到目前为止,我的想法如下:
graphics.DrawText
和DrawImage
代替许多标签来绘制“项目”。我希望这将意味着1个item=1用户对象,而不是13个
控件.DrawToBitmap()
方法获取图像,然后在FlowLayoutPanel
中使用该图像(或类似)DrawToBitmap
并显示控件的“重影图像”
或者,我假设这里正在进行一些滚动(没有人可以一次查看7280个UI对象,对吗?),因此,您可以做的另一件事是动态地只创建实际将同时出现在屏幕上的实例。您必须计算可见区域,并将其与要显示的控件列表进行比较,如果用户界面被放大得太大而无法实际显示任何细节,则只显示占位符。不过,我认为如果你这样做的话,滚动/缩放将成为一个相当CPU密集型的操作;最好不要创建它们。至少,我会从你的想法开始。这确实会将应用程序占用的窗口数量减少13倍 关于您的想法#2,如果您将位图放入PictureBox(或其他)中,从而在表单上有大量PictureBox控件,那么这对您毫无帮助(这可能更糟,因为位图有时由比普通RAM更有限的资源组成,这与占用太多窗口完全不同)。只有将生成的位图复制到单个较大的控件上(然后处理位图),这才是一个好主意 如果采用后一种方法,则实际上不需要使用渲染到控件的中间步骤,即获取控件的位图副本,然后将该位图绘制到最终控件上。采用渲染控件所用的代码/逻辑,而直接渲染到最终控件,这将更有意义(多元素)控制。我实施了#1,效果良好 用户对象减少13倍,而且感觉更快、响应更快
感谢您的建议-我很惊讶这不是一个更常见的问题!与创建数百个位图或图片框相比,我认为方法是将每个控件直接绘制到单个
图片框的图像,或者使用单个“精灵”位图并绘制所有控件。虽然它们实际上只是标签,但我认为使用TextRenderer
并完全绕过控件更容易-很难准确地说出需要在这里绘制什么。我会引导他远离TextRenderer
,因为它非常慢(相对于Graphics.DrawString
),但我同意他的最佳方法是将每个数据库行直接呈现给单个控件(最好只呈现可见的行)。