C# 提高WPF数据网格性能
在我的C# 提高WPF数据网格性能,c#,wpf,datagrid,wpfdatagrid,C#,Wpf,Datagrid,Wpfdatagrid,在我的.net3.5WPF应用程序中,我有一个WPFDataGrid,它将填充500列和50行。 应用程序的性能在滚动时非常差,或者在执行DataGrid.Items.Refresh()时,或者在选择行时非常差 实际上,应用程序将需要大约20秒来更新布局布局更新()事件将在20秒后触发 如果我将列数减少到50或更少,应用程序的响应速度将非常快。根据我的发现,性能与列数直接相关 如何提高数据网格的性能?也许可以尝试一下,而不是一次加载所有50行 您可以打开一些选项来帮助您处理数据网格对象 Enab
.net3.5
WPF
应用程序中,我有一个WPF
DataGrid
,它将填充500列和50行。
应用程序的性能在滚动时非常差,或者在执行DataGrid.Items.Refresh()时,或者在选择行时非常差
实际上,应用程序将需要大约20秒来更新布局<代码>布局更新()
事件将在20秒后触发
如果我将列数减少到50或更少,应用程序的响应速度将非常快。根据我的发现,性能与列数直接相关
如何提高数据网格的性能?也许可以尝试一下,而不是一次加载所有50行
您可以打开一些选项来帮助您处理数据网格对象
EnableColumnVirtualization = true
EnableRowVirtualization = true
这两个是我认为可能有帮助的主要因素。下一步尝试使绑定异步
ItemsSource="{Binding MyStuff, IsAsync=True}"
最后,我听说设置最大高度和宽度即使高于最大屏幕尺寸也有帮助,但我自己没有注意到差异(声称与自动尺寸测量有关)
另外,永远不要将
数据网格
放在滚动查看器
中,因为这样会基本上失去虚拟化。让我知道这是否有帮助 检查是否有属性ScrollViewer.CanContentScroll
设置False
。
将此属性设置为false将以某种方式禁用虚拟化,这将降低数据网格的性能。有关更多说明,请参阅此设置
DataGrid.RowHeight
值,这将产生巨大的差异
我知道这是一个非常古老的问题,但我刚刚遇到了它,这是我这边最大的不同。我的默认身高是25。第一步:2分钟到10秒
这个答案()使我走上了正确的轨道。但我需要将其设置为false
。为了在刷新时将其设置为true
,我编写了以下两种方法
internal static void DataGridRefreshItems(DataGrid dataGridToRefresh)
{
/// Get the scrollViewer from the datagrid
ScrollViewer scrollViewer = WpfToolsGeneral.FindVisualChildren<ScrollViewer>(dataGridToRefresh).ElementAt(0);
bool savedContentScrollState = scrollViewer.CanContentScroll;
scrollViewer.CanContentScroll = true;
dataGridToRefresh.Items.Refresh();
/// Was set to false, restore it
if (!savedContentScrollState)
{
/// This method finishes even when the update of the DataGrid is not
/// finished. Therefore we use this call to perform the restore of
/// the setting after the UI work has finished.
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => SetScrollViewerCanContentScrollFalse(scrollViewer)), DispatcherPriority.ContextIdle, null);
}
}
private static void SetScrollViewerCanContentScrollFalse(ScrollViewer scrollViewer)
{
scrollViewer.CanContentScroll = false;
}
内部静态无效DataGridRefreshItems(DataGrid dataGridToRefresh)
{
///从datagrid获取scrollViewer
ScrollViewer ScrollViewer=WpfToolsGeneral.FindVisualChildren(dataGridToRefresh).ElementAt(0);
bool savedContentScrollState=scrollViewer.CanContentScroll;
scrollViewer.CanContentScroll=true;
dataGridToRefresh.Items.Refresh();
///已设置为false,请还原它
如果(!savedContentScrollState)
{
///即使没有更新DataGrid,此方法也会完成
///已完成。因此,我们使用此调用来执行
///UI工作完成后的设置。
Dispatcher.CurrentDispatcher.BeginInvoke(新操作(()=>SetScrollViewerCanContentScrollFalse(scrollViewer)),DispatcherPriority.ContextIdle,null);
}
}
私有静态无效SetScrollViewerCanContentScrollFalse(ScrollViewer ScrollViewer)
{
scrollViewer.CanContentScroll=false;
}
这是我用来获取VisualChildren的方法:
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
公共静态IEnumerable FindVisualChildren(DependencyObject depObj),其中T:DependencyObject
{
if(depObj!=null)
{
for(int i=0;i
在此之后,我对50000个新项目的刷新只持续10秒,不像之前的2分钟那样,并且只消耗了2MB内存(4GB)
步骤2:10秒到0.5秒
为了进行测试,我禁用了所有
IValueConverter
,并实现了直接绑定的属性。如果没有转换器,DataGrid会立即刷新。所以我留下了它。一个包含10列以上的网格可能不是一个好主意。但是请考虑<代码>自定义分页< /代码> @ BoMeMe真的吗?见过外汇网格吗?@WPFK你有没有考虑过使用性能优化的第三方网格?@TomTom-你能告诉我一些第三方网格吗。我不知道外汇是什么,但我不认为任何理智的人都会浏览500列数据。谢谢你的建议。但是我的要求是一次有500列。你说滚动,所以我认为你不能一次显示所有的行(用500列怎么办)数据虚拟化的思想是加载一定数量的数据来填充网格,然后在滚动时删除和替换行。我还可以将列设置为固定宽度。@testpattern数据网格自行滚动,你只是不想把它放在你自己的ScrollViewer的DataGrid外部,否则你会失去控件的虚拟化。我想知道为什么其他线程从未讨论过这一点,即启用行和列虚拟化。非常感谢。绝对值得一试!事实上,他们为我提高了很多性能。感谢@Alan,设置MaxHeight取得了显著的改进。非常感谢你。同时设置MaxWidth也有轻微的改进。在找到这个解决方案之前,我都快疯了。非常感谢。
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}