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个

  • 拥有“项”的1个实例,然后对于每个记录,填充该实例并使用
    控件.DrawToBitmap()
    方法获取图像,然后在
    FlowLayoutPanel
    中使用该图像(或类似)

  • 所以。。。有人还有其他建议吗?

    另外,这是一个可缩放的界面,因此我已经排除了“分页”的可能性,因为需要同时查看所有项目

    您的想法#2是我推荐的。这正是用于显示数千条记录的列表和网格控件能够执行的操作。您只需从一个控件开始,然后将其移动到需要的任何位置

    如果您需要同时显示多个实例,则会有点困难-正如您所提到的,您很可能必须使用
    DrawToBitmap
    并显示控件的“重影图像”


    或者,我假设这里正在进行一些滚动(没有人可以一次查看7280个UI对象,对吗?),因此,您可以做的另一件事是动态地只创建实际将同时出现在屏幕上的实例。您必须计算可见区域,并将其与要显示的控件列表进行比较,如果用户界面被放大得太大而无法实际显示任何细节,则只显示占位符。不过,我认为如果你这样做的话,滚动/缩放将成为一个相当CPU密集型的操作;最好不要创建它们。

    至少,我会从你的想法开始。这确实会将应用程序占用的窗口数量减少13倍

    关于您的想法#2,如果您将位图放入PictureBox(或其他)中,从而在表单上有大量PictureBox控件,那么这对您毫无帮助(这可能更糟,因为位图有时由比普通RAM更有限的资源组成,这与占用太多窗口完全不同)。只有将生成的位图复制到单个较大的控件上(然后处理位图),这才是一个好主意

    如果采用后一种方法,则实际上不需要使用渲染到控件的中间步骤,即获取控件的位图副本,然后将该位图绘制到最终控件上。采用渲染控件所用的代码/逻辑,而直接渲染到最终控件,这将更有意义(多元素)控制。

    我实施了#1,效果良好

    用户对象减少13倍,而且感觉更快、响应更快


    感谢您的建议-我很惊讶这不是一个更常见的问题!

    与创建数百个位图或图片框相比,我认为方法是将每个控件直接绘制到单个
    图片框的图像,或者使用单个“精灵”位图并绘制所有控件。虽然它们实际上只是标签,但我认为使用
    TextRenderer
    并完全绕过控件更容易-很难准确地说出需要在这里绘制什么。我会引导他远离
    TextRenderer
    ,因为它非常慢(相对于
    Graphics.DrawString
    ),但我同意他的最佳方法是将每个数据库行直接呈现给单个控件(最好只呈现可见的行)。