c# – WPF DataGrid DataContext非常慢

我有一个简单的WPF应用程序,它正在执行SQL查询并在DataGrid中显示结果数据.

一切都按预期工作,除了表现很糟糕.单击按钮加载数据,实际看到数据显示在DataGrid中的时间长度大约为3-4秒.打开行虚拟化时速度要快一些,但由于我需要能够对滚动后不再可见的单元格执行操作,因此我不得不关闭它.即使启用了虚拟化,显示数据的速度也比我想要的慢.

我首先假设SQL数据库速度很慢,但我做了一些测试,发现我在几分之一秒内将所有数据从SQL服务器(几百行)读入DataTable.直到我将DataTable绑定到DataGrid的DataContext,所有内容都锁定了几秒钟.

那么为什么DataContext如此之慢?我的计算机是全新的,所以我很难理解为什么需要花费任何时间来填写DataGrid,考虑到我首先检索数据的速度有多快.

(我也尝试绑定到DataGrid的ItemSource而不是DataContext,但性能是相同的.)

是否有另一种方法将数据加载到具有更合理性能的DataGrid中?如果需要,即使是DataGrid的替代品也许值得探索.

编辑:在Vlad的建议下,我尝试了另一个绕过SQL查询的测试.我用DataTable填充了1000行随机生成的数据.没变.数据生成并在一秒钟内写入DataTable.但是,将其附加到DataGrid需要20多秒.

下面是我正在使用的DataGrid XAML.除了绑定之外,它非常简单,没有自定义代码.

<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False" Name="dataGridWellReadings" GridLinesVisibility="None" CanUserResizeRows="False" SelectionUnit="Cell" AlternatingRowBackground="#FFE0E0E0" RowBackground="#FFF0F0F0" HorizontalScrollBarVisibility="Disabled" SelectedCellsChanged="dataGridWellReadings_SelectedCellsChanged" EnableRowVirtualization="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Date" Binding="{Binding readingDate, StringFormat=yyyy-MM-dd}" Width="3*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="Pt" Binding="{Binding readingPt, StringFormat=0.#}" Width="2*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="Pc" Binding="{Binding readingPc, StringFormat=0.#}" Width="2*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="Ppl" Binding="{Binding readingPpl, StringFormat=0.#}" Width="2*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="MCFD" Binding="{Binding readingMCFD, StringFormat=0.#}" Width="2*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="Water Produced" Binding="{Binding readingWaterProduced, StringFormat=0.#}" Width="3*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="Water Hauled" Binding="{Binding readingWaterHauled, StringFormat=0.#}" Width="3*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="Temperature" Binding="{Binding readingTemperature, StringFormat=0.#}" Width="3*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="Hours On (actual)" Binding="{Binding readingHoursOnActual, StringFormat=0.#}" Width="3*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="Hours On (planned)" Binding="{Binding readingHoursOnPlanned, StringFormat=0.#}" Width="3*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
        <DataGridTextColumn Header="Clock Cycles" Binding="{Binding readingClockCycles, StringFormat=0.#}" Width="3*">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>
最佳答案
有太多变数可以肯定地回答这个问题.但是,您可以考虑以下事项:

>您为网格提供的数据量是否必要?您是否可能提供的数据太多而不是用户真正使用的数据?这会减慢速度.
>您是否使用太多模板渲染列或单元格?我知道,这使得您的演示文稿变得灵活,但是太多的模板(或控件)可能会减慢速度.
>您的数据网格中有很多值转换器吗?是否需要每行或每列运行一些稍微昂贵的代码才能呈现?
>您是否有可能拥有大量嵌套样式(使用BasedOn),或许更重要的是,这些样式中的许多触发器会窃取渲染时间?
>您是否在演示文稿中使用了大量用户控件(尤其是嵌套控件),这些控件可能会导致演示文稿中的渲染延迟?
>您用于细胞的绑定字符串是否复杂?应用许多StringFormat或ElementName或Ancestory查找?这些都会导致渲染速度变慢.
>是否有可能使用可视笔刷来显示比用户立即看到的更多数据?这会使虚拟化逻辑短路.
>您是否考虑过将FallBackValue用于绑定并将IsAsync设置为true?将此设置为tru将显示FallBackValue,直到数据准备就绪.
>您是否在UI中使用了许多MultiBindings或PriorityBindings,这可能导致渲染在处理多个字段或值时变慢?
>您使用的样式是否复杂?特别是渐变画笔,渲染它们可能会很昂贵,特别是如果你在网格中的每一行都这样做.
>您是否考虑过使用分页以减少数据量?最后,Nairou,如果你能让用户接受它,这是解决这些类型问题的最佳方案.
>您在看内存和CPU使用情况吗?您正在使用的硬件是否可能只是在努力渲染您在此处创建的UI?
>您是否正在观察调试输出以查看是否存在导致性能下降的绑定错误或其他吞噬错误?
>你是否对屏幕微笑并给你的代码一个良好的感觉所以它愿意为你更加努力?开个玩笑,但有很多变数 – 嗯?
>您是否实现了可以非常频繁地调用CanExecute处理程序并且执行起来可能很昂贵的命令?这些可能是沉默的表演杀手.

同样,这个问题没有100%的答案.但这些可能有所帮助.

还有一件事需要考虑,你的枚举可以是一个可观察的列表 – 这将允许你加载部分数据.如果你想加载第一页并在异步过程中附加下一页和下一页等等,那么用户体验应该非常接近于一次加载它,除非它是一个更快的初始渲染.这可能很复杂,但它是另一种选择.可观察列表非常漂亮.

像这样的东西:

ObservableCollection<User> Users { get; set; }

void LoadUsers()
{
    int _Size = 2;
    int _Page = 0;
    using (System.ComponentModel.BackgroundWorker _Worker
        = new System.ComponentModel.BackgroundWorker())
    {
        _Worker.WorkerReportsProgress = true;
        _Worker.DoWork += (s, arg) =>
        {
            List<User> _Data = null;
            while (_Data == null || _Data.Any())
            {
                _Data = GetData(_Size, _Page++);
                _Worker.ReportProgress(_Page, _Data);
            }
        };
        _Worker.ProgressChanged += (s, e) =>
        {
            List<User> _Data = null;
            _Data = e.UserState as List<User>;
            _Data.ForEach(x => Users.Add(x));
        };
        _Worker.RunWorkerAsync();
    }
}

List<User> GetData(int size, int page)
{
    // never return null
    return m_Context.Users.Take(size).Skip(page).ToList();
}

这就是我想要你带走的东西 – 在WPF中绑定永远不会是即时的.你将永远不会有一个复杂的表单渲染和绑定没有延迟.您可以使用上述一些技巧控制疼痛.但是,你永远不能删除它.但是,WPF中的绑定是最强大和最棒的绑定技术.我曾经历过.

祝你好运!

转载注明原文:c# – WPF DataGrid DataContext非常慢 - 代码日志