【问题标题】:WPF DataGrid and multithreadingWPF DataGrid 和多线程
【发布时间】:2012-06-23 11:03:19
【问题描述】:

我有一个用 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;
        }));
    }

提前致谢!

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

【问题讨论】:

  • 主 UI 线程创建 UI 对象并且是唯一可以访问 UI 对象的线程。您可以在背景踏板上使用 GetFieldsBLL()。如果您不需要编辑,请使用 ListView GridView,因为它更轻、更快。
  • 将答案标记为已接受通常是有礼貌的。否则人们下次不会再帮你了。

标签: c# wpf multithreading


【解决方案1】:

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

【讨论】:

  • 感谢您的快速回答!设置固定的列宽和行高肯定会使其渲染速度更快。我查看了您的代码,但我不明白“c”和“x”代表什么。能详细点吗?
  • 我删除了 c,它是我代码中的自定义命名空间别名。对不起。 x 只是传递给 lambda 委托的参数。它表示单元格的文本块内容,这是作为 arg 参数传递给 BeginInvoke 方法的内容。
【解决方案2】:

将 DispatcherPriority 更改为 Background。

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 我重新创建列的原因是因为某些列的名称中有一个点。例如“工作编号”。使用绑定时不会产生任何数据。在此处阅读更多信息:stackoverflow.com/questions/2940618/… 不能对数据库进行更改。
    【解决方案4】:

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

    将以下任务分配给 DoWork 回调

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

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

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-30
        • 2013-01-16
        • 2016-06-21
        • 2017-10-04
        • 1970-01-01
        相关资源
        最近更新 更多