3

我有一个用 DataView 填充的 DataGrid(使用 DataContext)。我试图在一个单独的线程中执行此操作,但 UI 仍然冻结。我想防止 UI 在填充 DataGrid 时冻结。

这是我到目前为止制作的代码:

private void btnOK_Click(object sender, RoutedEventArgs e)
    {
        GetFieldsBLL getFieldsBLL = new GetFieldsBLL();
        DataView dv = getFieldsBLL.GetWholeView(ViewName);
        Task task = new Task(() => ucDataExtracViewControl.PopulateGrid(dv));
        task.Start();
    }

public void PopulateGrid(DataView dv)
    {
        dgView.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate{

            dgView.Columns.Clear();
            dgView.AutoGenerateColumns = false;
            foreach (DataColumn column in dv.Table.Columns)
            {
                var gridColumn = new DataGridTextColumn()
                {
                    Header = column.ColumnName,
                    Binding = new Binding("[" + column.ColumnName + "]")
                };

                dgView.Columns.Add(gridColumn);
            }
            dgView.DataContext = dv;

            DataView = dv;
        }));
    }

提前致谢!

编辑:我重新创建列的原因是因为某些列名的名称中有一个点。例如“工作编号”。使用绑定时不会产生任何数据。在此处阅读更多内容:带点的 DataTable 列名称是什么导致它们不适合 WPF 的 DataGrid 控件?不能对数据库进行更改。——</p>

4

5 回答 5

3

我用 WPF DataGrid 做了很多工作,渲染是个问题。最后,渲染时间归结为您将要显示的列和行的数量。当 DataGrid 呈现时,它必须绘制每一个,这意味着加载和测量内容的大小。

我发现您可以通过设置固定的列宽和行高来提高速度。当与下面的 DelayedDataGridTextColumn 结合使用时,UI 线程的阻塞非常小,因为每个单元格都是单独渲染的,因此允许其他事情在具有更高优先级的 UI 线程上发生。

public class DelayedDataGridTextColumn : DataGridTextColumn
{
    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        var textBlock = new TextBlock();
        textBlock.SetValue(FrameworkElement.StyleProperty, ElementStyle);

        Dispatcher.BeginInvoke(
            DispatcherPriority.Loaded,
            new Action<TextBlock>(x => x.SetBinding(TextBlock.TextProperty, Binding)),
        textBlock);
        return textBlock;
    }
}

请注意,您可以调整 DispatcherPriority 以适应您想要的渲染速度。优先级越低,您获得的窗帘效果就越多。优先级越高,渲染时处理的其他项目就越少。

于 2012-06-21T08:49:25.227 回答
1

将 DispatcherPriority 更改为 Background。

dgView.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(delegate{
// your code
};
于 2012-06-21T11:08:49.457 回答
0

您实际上并没有在单独的线程中运行它,因为您要做的第一件事是将其分派回 UI 线程

问题是您为什么要自己重新创建列?AutoGenerateColumns这真的会产生与设置为 true不同的结果吗?

如果你能正确使用 WPF 的绑定特性,我认为你可以改进这一点,但只有很少的代码可以对此提出好的建议。

于 2012-06-21T08:37:40.030 回答
0

您可以使用 BackgroundWorker 类来执行后台进程意味着:

将以下任务分配给 DoWork 回调

  1. 调用 getFieldsBLL.GetWholeView(ViewName);
  2. 以您想要填充的方式填充 DataView

将 UI 更新代码 (dgView.DataContext = dv;) 移动到 RunWorkerCompleted 回调。

注意:您需要为 DataView 创建一个类变量,以便它可以用于 DoWork 和 RunWorkerCompleted 回调。

于 2012-06-21T14:10:59.550 回答
0

我解决了这个问题。C# 代码不是 UI 冻结的原因,而是 DataGrid 上记录的呈现。EnableRowVirtualization="True" EnableColumnVirtualization="True" ScrollViewer.CanContentScroll="True"在数据网格中设置

实际上 DataGrid 冻结了大数据的 UI。所以启用虚拟化解决了这个问题

于 2021-03-21T06:02:39.383 回答