gpt4 book ai didi

c# - Control.AddRange(...) 很慢

转载 作者:行者123 更新时间:2023-12-04 12:52:34 31 4
gpt4 key购买 nike

项目:我有一个包含 ComboBox 和 FlowLayoutPanel 的父面板。 FlowLayoutPanel 包含数量可变的子面板(继承自 UserControl 的自定义控件)。每个子面板包含一些标签、两个 ComboBox、一个按钮和一个具有 3 个 ComboBox 列和一个按钮列的 DataGridView。 DataGridView 可能有 1-6 行。当从父面板上的 ComboBox 中选择一个项目时,FlowLayoutPanel 会填充子面板。

enter image description here

问题:用大约 50 个子面板填充 FlowLayoutPanel 大约需要 2.5 秒。具体来说,我确定对 FlowLayoutPanel.Controls.AddRange() 的调用是罪魁祸首。

相关代码:我不能在这里发布我的所有代码(太多的代码加上部分代码是 secret 的),但我会尽力解释发生了什么。

家长面板:

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

我尝试过的事情:

  • 在父面板和/或 FlowLayoutPanel 上调用 SuspendLayout()/ResumeLayout()。最小的性能提升(~0.2 秒)。
  • 在组合框、按钮和 DataGridView 列上使用 Control.FlatStyle.Flat。最小的性能提升(~0.1 秒)。
  • 已验证我的所有控件均未使用透明背景色。
  • 将 ChildPanel.DoubleBuffered 和 ParentPanel.DoubleBuffered 设置为 true。
  • 在调用 AddRange() 之前将 FlowLayoutPanel 从其父项中移除并在之后重新添加它。

可能相关的内容:

  • 面板和控件使用 anchor (与自动调整大小或停靠相对)。
  • 我的控件是手动填充的,不使用 DataSource 属性。

编辑:解决方案:

@HighCore 的回答是正确的解决方案。不幸的是,我现在不会实现它(它可能会在未来发生),因为我找到了解决方法。解决方法并没有真正解决问题,只是掩盖了它,因此我没有将其作为答案发布。我发现如果“依赖项”选项卡不在顶部(即选择了“产品列表”选项卡),表单加载时间会缩短一半。这将加载时间减少到大约 1 秒,这是可以接受的。当正在加载数据并且“依赖项”选项卡位于顶部时,我切换到“产品列表”选项卡,在选项卡控件上方抛出一个深灰色框,中间显示“正在加载...”,加载数据,然后切换返回依赖项选项卡。

感谢大家的意见和建议,非常感谢。

最佳答案

发布此答案是因为 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>

代码隐藏(仅支持示例的样板)

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

然后使用 ElementHost 将其放入现有的 winforms UI 中:

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

var elementHost = new ElementHost
{
Dock = DockStyle.Fill,
Child = new ListBoxSample()
};

Controls.Add(elementHost);

}
}

结果:

enter image description here

  • 请注意,我添加了 100,000 条记录。尽管如此,由于内置 WPF UI Virtualization,响应时间(滚动和与 UI 交互时)立即 .
  • 另请注意,我使用的是 DataBinding这消除了在程序代码中操作 UI 元素的需要。这很重要,因为 WPF 可视化树是一个复杂的结构,而 DataBinding 始终是 WPF 中的首选方法。
  • 另请注意,通过调整窗体大小,UI 完全分辨率独立。您可以通过固定 ComboBoxes 并将 DataGrid 延伸到剩余空间来进一步自定义它。参见 WPF Layouts .
  • WPF Rocks. - 看看您可以用这么少的代码实现多少,而无需在第三方控件上花费大量 $$$。你真的应该永远忘记 winforms。
  • 您至少需要以 .Net 3.0 为目标,但强烈建议使用 4.0/4.5,因为 WPF 在早期版本中存在多个问题,这些问题已在 4.0 中修复。
  • 确保引用 PresentationCore.dllPresentationFramework.dllWindowsBase.dllSystem.Xaml.dllWindowsFormsIntegration.dll,所有这些都属于 .Net Framework 本身(没有第 3 方)

关于c# - Control.AddRange(...) 很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22922233/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com