wpf datagrid高刷引起界面卡顿问题探索

目录

一. 高刷错误方法:每更新一次数据,就数据驱动刷新datagird

1. UI矢量语言实现

2. UI下面的cs文件实现数据绑定(没有用ViewModel)

3. 运行结果及分析

二. 高刷改进方法:每更新一次数据,将数据选择性的放入队列,另外一个线程队列数据驱动刷新datagird

1. MainWindowViewModel.cs里面的绑定显示数据,和数据容器定义

2. 每秒最多把N个数据放入数据容器,同时需要把每秒的最后一次更新数据放入容器

三. 源码链接


一. 高刷错误方法:每更新一次数据,就数据驱动刷新datagird

两个datagrid控件,直接用线程刷新,具体实现如下:

1. UI矢量语言实现

< Border
    Grid.Row = "0"
    Height = "Auto"
    HorizontalAlignment = "Stretch"
    VerticalAlignment = "Stretch"
    Background = "AliceBlue" >

    < DataGrid
        x: Name = "dg_ModuleVara"
        Height = "200"
        HorizontalAlignment = "Stretch"
        VerticalAlignment = "Stretch"
        AutoGenerateColumns = "false"
        Background = "{StaticResource PrimaryBlackBrush}"
        BorderBrush = "{StaticResource BoxBackgroundBrush}"
        BorderThickness = "1"
        CanUserAddRows = "False"
        CanUserSortColumns = "False"
        ColumnWidth = "*"
        GridLinesVisibility = "All"
        HorizontalGridLinesBrush = "{StaticResource BoxBackgroundBrush}"
        HorizontalScrollBarVisibility = "Hidden"
        RowBackground = "{StaticResource PrimaryBlackBrush}"
        RowHeaderWidth = "0"
        SelectionUnit = "FullRow"
        VerticalGridLinesBrush = "{StaticResource BoxBackgroundBrush}"
        VerticalScrollBarVisibility = "Hidden" >
        < DataGrid.Columns >
            < DataGridTextColumn
                Width = "1*"
                Binding = "{Binding Name, Mode=OneWay}"
                Foreground = "White"
                IsReadOnly = "True" />
            < DataGridTextColumn
                Width = "1*"
                Binding = "{Binding DispValue, Mode=OneWay}"
                Foreground = "White"
                IsReadOnly = "True" />
        
    

< Border
    Grid.Row = "1"
    Height = "Auto"
    HorizontalAlignment = "Stretch"
    VerticalAlignment = "Stretch"
    Background = "AliceBlue" >

    < DataGrid
        x: Name = "dg_ModuleVara2"
        HorizontalAlignment = "Stretch"
        VerticalAlignment = "Stretch"
        AutoGenerateColumns = "false"
        Background = "{StaticResource PrimaryBlackBrush}"
        BorderBrush = "{StaticResource BoxBackgroundBrush}"
        BorderThickness = "1"
        CanUserAddRows = "False"
        CanUserSortColumns = "False"
        ColumnWidth = "*"
        GridLinesVisibility = "All"
        HorizontalGridLinesBrush = "{StaticResource BoxBackgroundBrush}"
        HorizontalScrollBarVisibility = "Hidden"
        RowBackground = "{StaticResource PrimaryBlackBrush}"
        RowHeaderWidth = "0"
        SelectionUnit = "FullRow"
        VerticalGridLinesBrush = "{StaticResource BoxBackgroundBrush}"
        VerticalScrollBarVisibility = "Hidden" >
        < DataGrid.Columns >
            < DataGridTextColumn
                Width = "1*"
                Binding = "{Binding Name, Mode=OneWay}"
                Foreground = "White"
                IsReadOnly = "True" />
            < DataGridTextColumn
                Width = "1*"
                Binding = "{Binding DispValue, Mode=OneWay}"
                Foreground = "White"
                IsReadOnly = "True" />
        
    

2. UI下面的cs文件实现数据绑定(没有用ViewModel)

public MainWindow()
{
    InitializeComponent();

    dg_ModuleVara.ItemsSource = null;
    dg_ModuleVara.ItemsSource = ModuleVaraList;
    dg_ModuleVara2.ItemsSource = null;
    dg_ModuleVara2.ItemsSource = ModuleVaraList2;
    Task.Run(() =>
    {
        while (true)
        {
            UpdateUiTool();
            UpdateUiTool2();
            Task.Delay(5).Wait();
        }
    });
}


/// 
/// 更新Ui1
/// 
/// 
private void UpdateUiTool()
{
    try
    {
        Random random = new Random();
        System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
        {
            ModuleVaraList.Clear();
            for (int imm = 0; imm < 10; imm++)
            {
                DispVara dispVara = new DispVara() { Name = $"标题{imm.ToString()}-{random.NextDouble()}", DispValue = $"内容{imm.ToString()}-{random.NextDouble()}" };
                ModuleVaraList.Add(dispVara);
            }
        }));
    }
    catch (Exception ex)
    {

    }
}

/// 
/// 更新Ui2
/// 
/// 
private void UpdateUiTool2()
{
    try
    {
        Random random = new Random();
        System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
        {
            ModuleVaraList2.Clear();
            for (int imm = 0; imm < 10; imm++)
            {
                DispVara dispVara = new DispVara() { Name = $"标题{imm.ToString()}-{random.NextDouble()}", DispValue = $"内容{imm.ToString()}-{random.NextDouble()}" };
                ModuleVaraList2.Add(dispVara);
            }
        }));
    }
    catch (Exception ex)
    {

    }
}

3. 运行结果及分析

运行5分钟后的内存占用情况

wpf datagrid高刷引起界面卡顿问题探索_第1张图片

现状:两个datagrid每秒刷新1000/2=200次/秒,界面相应迟钝,内存200M;五分钟左右涨到了2000M+,肉眼可见的刷新频率明显只有5次/秒,再继续没时间不测试了意义不大

原因分析:数据更新太快,被堆积了的大量消息(BeginInvoke),造成了内存增加,界面相应变慢

对策:一般的显示器刷新频率60或75HZ,数据刷新的太快了,屏幕显示不过来,就是显示过来了,眼睛也看不清,所以我们只需要把刷新频率限制到10次/秒,即可解决问题

待继续...

-------------------------------------------------------------------------------------------------------------------------

二. 高刷改进方法:每更新一次数据,将数据选择性的放入队列,另外一个线程队列数据驱动刷新datagird

1. MainWindowViewModel.cs里面的绑定显示数据,和数据容器定义

//工具显示绑定数据
private ObservableCollection _moduleVaraList = new ObservableCollection();
public ObservableCollection ModuleVaraList
{
    get
    {
        return _moduleVaraList;
    }
    set
    {
        _moduleVaraList = value;
        OnPropertyChanged("ModuleVaraList");
    }
}
//工具显示绑定数据
private ObservableCollection _moduleVaraList2 = new ObservableCollection();
public ObservableCollection ModuleVaraList2
{
    get
    {
        return _moduleVaraList2;
    }
    set
    {
        _moduleVaraList2 = value;
        OnPropertyChanged("ModuleVaraList2");
    }
}


//工具显示数据容器,每秒钟只再容器中放入10个数据
private Queue> _moduleVaraContainer = new Queue>();
public Queue> ModuleVaraListContainer
{
    get
    {
        return _moduleVaraContainer;
    }
    set
    {
        _moduleVaraContainer = value;
    }
}
//工具显示数据容器,每秒钟只再容器中放入10个数据
private Queue> _moduleVaraContainer2 = new Queue>();
public Queue> ModuleVaraListContainer2
{
    get
    {
        return _moduleVaraContainer2;
    }
    set
    {
        _moduleVaraContainer2 = value;
    }
}

2. 每秒最多把N个数据放入数据容器,同时需要把每秒的最后一次更新数据放入容器

/// 
/// 更新Ui容器
/// 
/// 
private void UpdateUiContainer()
{
    try
    {
        Random random = new Random();
        List temp = new List();
        for (int imm = 0; imm < 10; imm++)
        {
            DispVara dispVara = new DispVara() { Name = $"标题{imm.ToString()}-{random.NextDouble()}", DispValue = $"内容{imm.ToString()}-{random.NextDouble()}", GenerateTime = DateTime.Now };
            temp.Add(dispVara);
        }
        if (ModuleVaraListContainer.Count == 0 && _lastDispVara.Count == 0)
        {
            if (temp.Count > 0)
            {
                _lastDispVara = new List(temp);
                ModuleVaraListContainer.Enqueue(temp);
            }
        }
        else
        {
            if(temp.Count > 0)
            {
                if((temp[0].GenerateTime - _lastDispVara[0].GenerateTime).TotalMilliseconds >= 1000.0 / (_showTimesMaxSencond*1.0))
                {
                    ModuleVaraListContainer.Enqueue(temp);
                    _lastDispVara.Clear();
                    _lastDispVara = new List(temp);
                }
                else if ((temp[0].GenerateTime - _lastDispVara[0].GenerateTime).Seconds == 1)//每秒的最后一次更新,需要加到显示容器
                {
                    ModuleVaraListContainer.Enqueue(_lastDispVara);
                    ModuleVaraListContainer.Enqueue(temp);
                    _lastDispVara.Clear();
                    _lastDispVara = new List(temp);
                }
                else
                {
                    //放弃显示
                }
            }
        }

    }
    catch (Exception ex)
    {

    }
}

效果视频如下:

datagird通过数据容器刷新

三. 源码链接

(19条消息) Wpfdatagrid高刷问题解决方案-C#文档类资源-CSDN文库

参考资料:

WPF绘制图表时,1ms更新一次数据,界面变得特别卡? - 知乎 (zhihu.com)

wpf datagrid卡顿是什么原因? - 知乎 (zhihu.com)

你可能感兴趣的:(工业机器视觉-视觉软件平台应用,C#,wpf)