将大型数据集分配给DataGrid后似乎有延迟。在分配到ItemsSource或DataSource完成后,此延迟发生,并且是非阻塞的。特别是,在分配大量数据(大约200,000个元素)作为DataGrid的源之后,在项目出现在屏幕上之前有3-4秒的延迟。我确信这是在赋值后发生的并且是非阻塞的,因为赋值后的所有代码都会立即执行。
DataGrid中是否有任何可能有助于减少我遇到的延迟的设置,更重要的是,有什么方法可以知道该过程何时完成且项目在屏幕上可见,以便我可以通知流程的用户以及何时完成?
我尝试过优化的内容:
此外,DataGrid仅包含在用于定位的网格中,没有包含ScrollViewer或任何此类性质的网格,我使用this之类的东西将数据绑定到DataGrid。
我尝试过通知的内容:
我愿意接受进一步优化的建议,但确实需要找到一种方法来了解信息在屏幕上何时可见。延迟是可以接受的,并且可能随着数据集的大小增加,但我需要一种方法来让用户知情。
XAML:
<Window x:Class="WPF_NPS.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="480" Width="640">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DataGrid Grid.Row="1" AutoGenerateColumns="True" Name="DataGrid" ItemsSource="{Binding Data}" VerticalContentAlignment="Stretch"
HorizontalAlignment="Stretch" CanUserReorderColumns="False" CanUserSortColumns="False" IsReadOnly="True"
ColumnWidth="*" />
</Grid>
</Window>
C#可以在&#34;我尝试优化&#34;
的链接下找到答案 0 :(得分:0)
您可以使用BusyIndicator中包含的免费Extended WPF Toolkit™ Community Edition控件:
您只需要设置IsBusy
属性,它将如下所示,使用异步Task
,如下所示,启用它,执行操作,禁用它。
您应该使用IProgress<T>
,因为它是运行后台任务的“官方”方式,正如您在下面看到的那样,它不如BackgroundWorker
那么繁琐。
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace WpfApplication2
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
// simulate some long work
IProgress<double> progress = new Progress<double>(handler);
Action action = () =>
{
int length = 10;
for (int i = 0; i < length; i++)
{
Thread.Sleep(3000);
double d = 1.0d/length*(i + 1);
progress.Report(d);
}
};
await Task.Run(action);
}
private void handler(double value)
{
ProgressBar.Value = value*100;
}
}
}
最后一件事,
最好使用DataContext,而不是手动分配ItemsSource
。
在您的XAML上,只需按如下方式定义数据网格:
<DataGrid ItemsSource="{Binding}" />
然后在您的代码上使用它:
public partial class MainWindow : Window
{
public MyObject MyObject { get; private set; }
public MainWindow()
{
InitializeComponent();
MyObject = new MyObject();
this.DataContext = MyObject;
}
private void DoSomething()
{
MyObject.DoSomething();
}
}
尽量避免直接操纵数据网格,这样只会让你的生活更轻松。
要明确问题
我不知道一个机制告诉你DataGrid
进程在哪里,但是通过使用上面出现的控件,这肯定是一个很好的用户体验,他被告知他有等待,期间。
此外,您可以提供取消按钮,但我不确定这是否适合您的情况。
答案 1 :(得分:0)
虽然我从来没有找到要挂钩的事件,所以当完成渲染时我会收到通知,但我确实从各种评论和答案中进行了大量优化。这主要是通过放弃使用反射更快的实现来完成的。
首先,代替为我的DataGrid源使用自定义类,它提供了一个包含多个公共属性的自定义类的简单数组。这些属性是根据Excel互操作读取的数据设置的(LINQ to Excel替代方案被提出结果比我自己的解决方案慢)。这与数据网格绑定,并且对于100k行,加载时间减少到几秒钟,总共大约200k-500k单元。
在构建项目数组并将其绑定到DataGrid之后仍然可以找到该延迟,但延迟比以前更容易接受。
最后,因为我需要能够从文件中读取而不知道我想要哪些列,直到用户在运行时指定,我构建了一个系统来生成动态填充的类。我这样做是通过构建一个包含此类类代码的字符串,然后使用C#的运行时编译功能来获得接近硬编码类的效率。
最后,为了避免必须使用反射为这些自定义对象中的属性赋值,我构建了一个简单的接口,指定了一个方法,该方法从电子表格中获取通用数据行并在内部初始化属性。
这是界面:
namespace MyNamespace {
// Used by classes built by an ExcelQueryableFactory to permit
// initialization without knowledge of the underlying properties.
public interface IExcelQueryable {
void BuildFrom(object[] data);
}
}
以下是为其中一个自定义类生成的代码示例:
namespace MyNamespace {
public class CustomClass0 : IExcelQueryable {
public double myNumber { get; set; }
public string myString { get; set; }
public void BuildFrom(object[] data) {
myNumber = (double)data[0];
myString = (string)data[1];
}
}
}
它绝对不是我写过的最好的代码,但我想我还是会分享它,因为其他人出现了类似的问题。