C# WPF数据网格分组导致可怕的内存消耗
我就是搞不懂数据网格分组有什么不对 我有这样一个最小的应用程序:C# WPF数据网格分组导致可怕的内存消耗,c#,wpf,C#,Wpf,我就是搞不懂数据网格分组有什么不对 我有这样一个最小的应用程序: public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); List<Rec> data = new List<Rec>(); var rnd = new Random(); for (int i = 0
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<Rec> data = new List<Rec>();
var rnd = new Random();
for (int i = 0; i < 3000; i++)
{
data.Add(new Rec() { Group = string.Format("Group{0}", rnd.Next(1,3)), Name = string.Format("Item{0}", rnd.Next(1,50)), Age = rnd.Next(10,100) });
}
var dataView = new ListCollectionView(data);
dataView.GroupDescriptions.Add(new PropertyGroupDescription("Group"));
dataGrid.ItemsSource = dataView;
}
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
列表数据=新列表();
var rnd=新随机数();
对于(int i=0;i<3000;i++)
{
data.Add(new Rec(){Group=string.Format(“Group{0}”,rnd.Next(1,3)),Name=string.Format(“Item{0}”,rnd.Next(1,50)),Age=rnd.Next(10100)});
}
var dataView=新的ListCollectionView(数据);
添加(新属性GroupDescription(“组”);
dataGrid.ItemsSource=dataView;
}
}
以及它的XAML:
<Window x:Class="dggrouping_test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:dggrouping_test"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="dataGrid">
<DataGrid.GroupStyle>
<x:Static Member="GroupStyle.Default"/>
</DataGrid.GroupStyle>
</DataGrid>
</Grid>
当我编译并运行这个应用程序时,3000行的内存消耗大约550MB(!!!)。加载需要几秒钟。如果我只是注释dataView.GroupDescriptions.Add(…)并再次运行,内存使用率将下降到85MB。因此,在一个最小的示例中,每3000行消耗450 MB。我做错了什么?答案不止一个 设计 3000行不是一个小数目。我的经验是,100个字段/条信息是您应该向用户显示的限制。每行需要的字段越多,您应该显示的行就越少(减少到5-10行),而他甚至无法处理更多的内容 在查询过程中尽可能多地进行筛选。如果您的DBMS支持分页,也可以使用它。检索所有,然后在GUI中进行过滤是一个常见的错误。3000看起来很简单 UI虚拟化 XAML的设计考虑了很多问题。问题是,只有当它被打开,并且你暴露了正确的东西,它才能工作 绑定垃圾邮件 用户界面更新代价高昂。对于每个用户触发的事件,仅执行一次并不重要。但是,如果从任何形式的循环运行,它都会成为一个问题。我为此问题编写了一些示例代码:
using System;
using System.Windows.Forms;
namespace UIWriteOverhead
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int[] getNumbers(int upperLimit)
{
int[] ReturnValue = new int[upperLimit];
for (int i = 0; i < ReturnValue.Length; i++)
ReturnValue[i] = i;
return ReturnValue;
}
void printWithBuffer(int[] Values)
{
textBox1.Text = "";
string buffer = "";
foreach (int Number in Values)
buffer += Number.ToString() + Environment.NewLine;
textBox1.Text = buffer;
}
void printDirectly(int[] Values){
textBox1.Text = "";
foreach (int Number in Values)
textBox1.Text += Number.ToString() + Environment.NewLine;
}
private void btnPrintBuffer_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(10000);
MessageBox.Show("Printing with buffer");
printWithBuffer(temp);
MessageBox.Show("Printing done");
}
private void btnPrintDirect_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(1000);
MessageBox.Show("Printing directly");
printDirectly(temp);
MessageBox.Show("Printing done");
}
}
}
使用系统;
使用System.Windows.Forms;
命名空间UIWriteOverhead
{
公共部分类Form1:Form
{
公共表格1()
{
初始化组件();
}
int[]getNumbers(int上限)
{
int[]ReturnValue=新int[上限];
for(int i=0;i
现在几乎没有什么事情能像过多的更改通知那样导致UI更新。在执行类似于这样的处理工作时删除UI的集合,以便在完成后重新绑定它,这可能是有益的
一般模式
XAML和WPF/UWP的设计考虑了MVVM模式。虽然您可以使用其他方法,但您会错过大约90%的功能,每隔一步就会遇到问题。在我看来,您的代码不是一个合适的MVVM模式(窗口中的初始化代码泄露了它;排序/筛选部分也没有使用CollectionView)
如果你遵循这种模式,你所遇到的问题很有可能永远不会存在。无论哪种情况,如果您计划在XAML中进行任何严肃的工作,都值得学习。几年前,我写了一篇MVVM简介:
内存问题?
虽然速度问题是真实存在的,但内存问题并非必然存在。这很容易理解
很多人误解了垃圾收集器在设计上是相当懒惰的。如果它在应用程序关闭时只收集一次,那么这是理想的情况。因此,内存使用量可以增加而不存在任何问题。您可以通过调用GC.Collect()进行测试来检查是否存在内存泄漏。但是在life应用程序中,它不应该出现(而是选择一个合适的GC策略) 解决了附加属性的问题。它在.NET4.5及更高版本上工作
<DataGrid x:Name="dataGrid" VirtualizingPanel.IsVirtualizingWhenGrouping="True">
<!-...-->
</DataGrid>
分组阻止了行虚拟化,这会导致为每一行创建UI元素,甚至是那些偏离屏幕的元素。这是一个很好的提示。谢谢在谷歌上搜索时,我发现了一个virtualzingpanel.isvirtualzingwengroup附加属性,它解决了一个问题。