You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无缝更新绑定Dataset的仪表板DataGrid,解决运行时刷新闪烁问题

问题描述

我有一个用于仪表板展示的DataGrid,包含两列数据,行数由用户在启动前选择,运行时数据最高每秒更新1次。
配图
当前遇到的问题是:运行时通过修改关联的Dataset来更新DataGrid内容时会产生明显闪烁。

第一种实现方案代码如下:

dtsWatch.Tables[0].Rows.Clear();// <----- 此处触发闪烁
foreach (...required keyword...)
{
    ...
    dtsWatch.Tables[0].Rows.Add(label, value);// <---- 此处触发闪烁
    ...
}
dtgWatch.ItemsSource = dtsWatch.Tables[0].DefaultView;// <---- 此处触发闪烁

第二种方案基于「将DataGrid与Dataset解绑,先在临时数据集上完成修改再重新绑定」的思路实现,代码如下:

dtvTemp = (DataView)dtgWatch.ItemsSource;// <--- 从datagrid克隆临时数据集
dtgWatch.ItemsSource = dtvTemp;// <------------- 将datagrid绑定到临时数据集
dtsWatch.Tables[0].Rows.Clear();// <------------ 重置已解绑的主数据集
foreach (...required keyword...)
{
    ...
    dtsWatch.Tables[0].Rows.Add(label, value);// <--- 给已解绑的主数据集新增行
    ...
}
dtgWatch.ItemsSource = dtsWatch.Tables[0].DefaultView;// <---- 重新绑定主数据集

我采用上述方案是因为WPF中没有找到更新Dataset时冻结DataGrid刷新的相关指令,但第二种方案也完全没有减轻闪烁问题。请问针对DataGrid更新场景,还有没有其他更优的实现方案?

解决方案
  • 方案1:用控件生命周期方法挂起批量更新期间的渲染

WPF的DataGrid自带BeginInit()/EndInit()方法,可以在批量修改数据前挂起控件的布局和渲染刷新,所有数据修改完成后再一次性刷新界面,避免每次修改行数据触发逐次重绘:

// 开始批量更新前挂起渲染
dtgWatch.BeginInit();

dtsWatch.Tables[0].Rows.Clear();
foreach (...required keyword...)
{
    dtsWatch.Tables[0].Rows.Add(label, value);
}
dtgWatch.ItemsSource = dtsWatch.Tables[0].DefaultView;

// 全部修改完成后恢复渲染,一次性刷新
dtgWatch.EndInit();
  • 方案2:避免重复增删行,直接更新已有行数据

你的场景中行数是启动前固定的,完全不需要每次更新都清空、新增行,直接修改已有行的单元格值即可,大幅减少布局重算开销:

int rowIdx = 0;
foreach (...required keyword...)
{
    // 直接修改对应行的两个列值,不触发行增删的重绘逻辑
    dtsWatch.Tables[0].Rows[rowIdx][0] = label;
    dtsWatch.Tables[0].Rows[rowIdx][1] = value;
    rowIdx++;
}
  • 方案3:优化DataGrid渲染配置

可以在XAML中给DataGrid添加以下配置降低重绘开销:

<DataGrid x:Name="dtgWatch"
          CacheMode="BitmapCache"
          EnableColumnVirtualization="False"
          EnableRowVirtualization="False"
          ScrollViewer.CanContentScroll="False">
    <!-- 列配置 -->
</DataGrid>

注:行数量较少时关闭虚拟化可以减少虚拟化切换带来的额外开销,行数超过50行不建议关闭

  • 方案4:替换绑定源为强类型集合

相比DataSet的粗粒度通知,用实现了INotifyPropertyChanged的强类型类配合ObservableCollection<T>作为绑定源,更新单个属性只会触发对应单元格的刷新,性能提升最明显:

// 定义行数据类
public class WatchItem : INotifyPropertyChanged
{
    private string _label;
    public string Label
    {
        get => _label;
        set { _label = value; OnPropertyChanged(); }
    }
    private string _value;
    public string Value
    {
        get => _value;
        set { _value = value; OnPropertyChanged(); }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

// 初始化绑定(启动时执行一次即可)
ObservableCollection<WatchItem> WatchItems = new ObservableCollection<WatchItem>();
dtgWatch.ItemsSource = WatchItems;

// 运行时更新逻辑,无需修改绑定源
int rowIdx = 0;
foreach (...required keyword...)
{
    WatchItems[rowIdx].Label = label;
    WatchItems[rowIdx].Value = value;
    rowIdx++;
}

内容的提问来源于stack exchange,提问作者Patrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 19:15:07