WPF DataGrid和多线程

时间:2012-06-21 08:28:37

标签: c# wpf multithreading

我有一个DataGrid,我用DataView填充(使用DataContext)。我试图在一个单独的线程中做到这一点,但UI仍然冻结。我想在填充DataGrid时阻止UI冻结。

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

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

提前致谢!

编辑: 我重新创建列的原因是因为某些列名称的名称中有一个点。例如,“作业编号”在使用绑定时不会产生任何数据。在此处阅读更多内容:What is it about DataTable Column Names with dots that makes them unsuitable for WPF's DataGrid control?不能对数据库进行更改。 -

5 个答案:

答案 0 :(得分:2)

我在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以适应所需的渲染速度。优先级越低,您获得的幕布效果越多。优先级越高,渲染时处理的其他项就越少。

答案 1 :(得分:1)

将DispatcherPriority更改为背景。

dgView.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(delegate{
// your code
};

答案 2 :(得分:0)

你实际上并没有在一个单独的线程中运行它,因为你要做的第一件事是将它发送回UI-Thread

问题是为什么你自己重新创建列? 这确实会产生与将AutoGenerateColumns设置为true无关的结果吗?

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

答案 3 :(得分:0)

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

将以下任务分配给DoWork回调

  1. 调用getFieldsBLL.GetWholeView(ViewName);
  2. 以您希望填充的方式填充DataView
  3. 将UI更新代码(dgView.DataContext = dv;)移至RunWorkerCompleted回调。

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

答案 4 :(得分:0)

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

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