C# 控件。AddRange(…)速度较慢
项目: 我有一个包含ComboBox和FlowLayoutPanel的父面板。FlowLayoutPanel包含数量可变的子面板(从UserControl继承的自定义控件)。每个子面板包含一些标签、两个组合框、一个按钮和一个DataGridView,其中包含3个组合框列和一个按钮列。DataGridView可能有1-6行。当从父面板上的组合框中选择项目时,FlowLayoutPanel将填充子面板 问题: 用大约50个子面板填充FlowLayoutPanel大约需要2.5秒。具体来说,我已经确定对FlowLayoutPanel.Controls.AddRange()的调用是罪魁祸首 相关代码:我不能在这里发布我所有的代码(太多的代码加上部分代码是保密的),但我会尽力解释发生了什么 父面板:C# 控件。AddRange(…)速度较慢,c#,.net,winforms,.net-2.0,flowlayoutpanel,C#,.net,Winforms,.net 2.0,Flowlayoutpanel,项目: 我有一个包含ComboBox和FlowLayoutPanel的父面板。FlowLayoutPanel包含数量可变的子面板(从UserControl继承的自定义控件)。每个子面板包含一些标签、两个组合框、一个按钮和一个DataGridView,其中包含3个组合框列和一个按钮列。DataGridView可能有1-6行。当从父面板上的组合框中选择项目时,FlowLayoutPanel将填充子面板 问题: 用大约50个子面板填充FlowLayoutPanel大约需要2.5秒。具体来说,我已经确
private void displayInformation(Suite suite)
{
this.SuspendLayout();
// Get dependencies.
List<SuiteRange> dependents = new List<SuiteRange>(suite.dependencies.Keys);
dependents.Sort(SuiteRange.Compare);
// Create a ChildPanel for each dependent.
List<ChildPanel> rangePanels = new List<ChildPanel>();
foreach (SuiteRange dependent in dependents)
{
ChildPanel sdp = new ChildPanel();
sdp.initialize(initialSuite.name, dataAccess);
sdp.displayInformation(dependent, suite.dependencies[dependent]);
rangePanels.Add(sdp);
}
// Put the child panels in the FlowLayoutPanel.
flpDependencyGroups.SuspendLayout();
// Takes ~2.5 seconds
flpDependencyGroups.Controls.AddRange(rangePanels.ToArray());
flpDependencyGroups.ResumeLayout();
// Takes ~0.5 seconds
updateChildPanelSizes();
this.ResumeLayout();
}
private void显示信息(套件)
{
这个.SuspendLayout();
//获取依赖项。
列表依赖项=新列表(suite.dependentials.Keys);
dependents.Sort(SuiteRange.Compare);
//为每个依赖项创建一个子面板。
列表范围面板=新列表();
foreach(从属中的SuiteRange dependent)
{
ChildPanel sdp=新的ChildPanel();
初始化(initialSuite.name,dataAccess);
显示信息(依赖,套件依赖[依赖]);
范围面板。添加(sdp);
}
//将子面板放入FlowLayoutPanel中。
flpDependencyGroups.SuspendLayout();
//大约需要2.5秒
flpDependencyGroups.Controls.AddRange(rangePanels.ToArray());
flpDependencyGroups.ResumeLayout();
//大约需要0.5秒
UpdateChildPanelizes();
这是resumeloayout();
}
我尝试过的事情:
- 在父面板和/或FlowLayoutPanel上调用SuspendLayout()/ResumeLayout()。最低性能提升(约0.2秒)
- 在组合框、按钮和DataGridView列上使用Control.FlatStyle.Flat。最低性能提升(约0.1秒)
- 已验证我的控件均未使用透明背景色
- 将ChildPanel.DoubleBuffered和ParentPanel.DoubleBuffered设置为true
- 在调用AddRange()并在之后重新添加之前,请从其父级移除FlowLayoutPanel
- 面板和控件使用定位(与自动调整大小或停靠相反)
- 我的控件是手动填充的,不使用DataSource属性
感谢大家的意见和建议,非常感谢。发布此答案,因为OP要求: 以下是在WPF中执行类似操作的方式:
<UserControl x:Class="WpfApplication7.ListBoxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel>
<Button Content="Load" Click="Load_Click" DockPanel.Dock="Top"/>
<ListBox ItemsSource="{Binding}"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="LightGray" BorderThickness="1" Padding="5"
Background="#FFFAFAFA">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Dependent Versions" FontWeight="Bold"
Grid.ColumnSpan="2" HorizontalAlignment="Center"/>
<TextBlock Text="From:" FontWeight="Bold"
Grid.Row="1" HorizontalAlignment="Center"/>
<TextBlock Text="To (exclusive):" FontWeight="Bold"
Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center"/>
<ComboBox SelectedItem="{Binding From}"
ItemsSource="{Binding FromOptions}"
Grid.Row="2" Margin="5"/>
<ComboBox SelectedItem="{Binding To}"
ItemsSource="{Binding ToOptions}"
Grid.Row="2" Grid.Column="1" Margin="5"/>
<DataGrid ItemsSource="{Binding ChildItems}"
AutoGenerateColumns="False" CanUserAddRows="False"
Grid.Column="2" Grid.RowSpan="4">
<DataGrid.Columns>
<DataGridTextColumn Header="XXXX" Binding="{Binding XXXX}"/>
<DataGridTextColumn Header="Dependee From" Binding="{Binding DependeeFrom}"/>
<DataGridTextColumn Header="Dependee To" Binding="{Binding DependeeTo}"/>
<DataGridTemplateColumn Width="25">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="X"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Content="Delete"
Grid.Column="3"
HorizontalAlignment="Right" VerticalAlignment="Top"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</UserControl>
结果:
- 请注意,我添加了100000条记录。尽管如此,由于WPF的内置,响应时间(在滚动和与UI交互时)仍然是即时的
- 还请注意,我使用的是,它消除了在过程代码中操作UI元素的需要。这一点很重要,因为WPF可视化树是一个复杂的结构,数据绑定始终是WPF中的首选方法
- 通过调整表单的大小,还可以注意到UI完全与分辨率无关。您可以通过固定组合框并将
延伸到剩余空间来进一步定制它。看DataGrid
- wpfrocks.-看看你能用这么少的代码实现多少,而不用在第三方控件中花费大量的$$$。你真的应该永远忘记winforms
- 您至少需要以.NET3.0为目标,但强烈建议使用4.0/4.5,因为WPF在早期版本中存在几个问题,这些问题在4.0中已修复
- 确保引用了
,PresentationCore.dll
,PresentationFramework.dll
,WindowsBase.dll
和System.Xaml.dll
,所有这些都属于.Net Framework本身(无第三方)WindowsFormsIntegration.dll
public partial class ListBoxSample : UserControl
{
public ListBoxSample()
{
InitializeComponent();
}
public void LoadData()
{
Task.Factory.StartNew(() =>
{
var list = new List<DataItem>();
for (int i = 0; i < 100000; i++)
{
var item = new DataItem()
{
From = "1",
To = "2",
ChildItems =
{
new ChildItem()
{
DependeeFrom = i.ToString(),
DependeeTo = (i + 10).ToString(),
XXXX = "XXXX"
},
new ChildItem()
{
DependeeFrom = i.ToString(),
DependeeTo = (i + 10).ToString(),
XXXX = "XXXX"
},
new ChildItem()
{
DependeeFrom = i.ToString(),
DependeeTo = (i + 10).ToString(),
XXXX = "XXXX"
}
}
};
list.Add(item);
}
return list;
}).ContinueWith(t =>
{
Dispatcher.Invoke((Action) (() => DataContext = t.Result));
});
}
private void Load_Click(object sender, System.Windows.RoutedEventArgs e)
{
LoadData();
}
}
public class DataItem
{
public List<ChildItem> ChildItems { get; set; }
public List<string> FromOptions { get; set; }
public List<string> ToOptions { get; set; }
public string From { get; set; }
public string To { get; set; }
public DataItem()
{
ChildItems = new List<ChildItem>();
FromOptions = Enumerable.Range(0,10).Select(x => x.ToString()).ToList();
ToOptions = Enumerable.Range(0, 10).Select(x => x.ToString()).ToList();
}
}
public class ChildItem
{
public string XXXX { get; set; }
public string DependeeFrom { get; set; }
public string DependeeTo { get; set; }
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var elementHost = new ElementHost
{
Dock = DockStyle.Fill,
Child = new ListBoxSample()
};
Controls.Add(elementHost);
}
}