更改源时DataGrid更新不起作用

Posted

技术标签:

【中文标题】更改源时DataGrid更新不起作用【英文标题】:DataGrid update not working when changed source 【发布时间】:2022-01-20 02:36:16 【问题描述】:

这是我的 DataGrid 测试代码。我使用 ObservableCollection 在 DataGrid 源上设置了一些数据并将其绑定。我修改了 ObservableCollection 成员属性的值。在这种情况下,我的 UI 必须显示该值已更改。但是,我的 DataGrid 仅在我选择单元格时进行交互。

绑定

public ObservableCollection<MyClass> griddata  get; set;  = new ObservableCollection<MyClass>();

我的班级

public class MyClass

    public int num  get; set; 
    public int idxnumber  get; set; 

XAML

<Grid>
    <DataGrid ItemsSource="Binding griddata, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged" >
    </DataGrid>
</Grid>

功能

//... griddata.add(someOfData);
public void ViewModel()

    int i = 0;
    while(i < 30)
    
        testing(0);
        i++;
    


private void testing(int idxnum)

    var test = griddata.Where(z => z.idxnumber == idxnum).FirstOrDefalut();
    test.num += 1;

结果 单元格值显示0和我选择的值立即更改为30

预期结果 单元格值连续显示030

编辑: 这是我的全部代码:

XAML

<Window x:Class="TestSol3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestSol3"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Grid>
        <DataGrid ItemsSource="Binding griddata">
            
        </DataGrid>
    </Grid>
</Window>

Model.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestSol3

    public class Model
    
        public int num  get; set; 
        public int idxnumber  get; set; 
    

ViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestSol3

    public class ViewModel
    
        public ObservableCollection<Model> griddata  get; set;  = new ObservableCollection<Model>();

        public ViewModel()
        
            griddata.Add(new Model()  num = 0, idxnumber = 0 );
            griddata.Add(new Model()  num = 1, idxnumber = 1 );

            Load(0);
        

        private void Load(int idxnum)
        
            int i = 0;
            while(i < 30)
            
                i++;
                griddata[idxnum].num++;
                //Thread.Sleep(200);
            
        
    

【问题讨论】:

while (i &lt; 30)中添加Thread.Sleep(100);会减慢UI中的值更新速度 @cg-zhou 不工作。我也试过Thread.sleep()Task.Delay,但这并没有帮助。 我尝试按照你的描述构建一个项目,由于缺少部分代码,这似乎很难;如果你提供可运行的 xx.xaml.cs 和 xx.cs,那将有很大帮助。 【参考方案1】:

尝试在你的模型中实现 INotifyPropertyChanged

namespace TestSol3

    public class ViewModel : INotifyPropertyChanged
    
        public ObservableCollection<Model> _griddata = new ObservableCollection<Model>();
        public ObservableCollection<Model> griddata 
         
            get => _griddata;
            set
            
                _griddata= value;
                OnChangedProperty("griddata");
            
        

        public void OnChangedProperty(string name)
        
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        
    

【讨论】:

【参考方案2】:

[解决方案]

在WPF中,你可以从Application.Current.Dispatcher得到dispatcher

How to pass the UI Dispatcher to the ViewModel

我们需要更改ObservableCollection中的项目以通知值更改事件。

ObservableCollection 的文档说:

表示一个动态数据集合,在添加、删除项目或刷新整个列表时提供通知。

https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=net-6.0

private void Load(int idxnum)

    Task.Run(() =>
    
        int i = 0;
        while (i < 30)
        
            i++;
            var model = griddata[idxnum];
            model.num++;

            var dispatcher = Application.Current.Dispatcher;
            dispatcher.Invoke(() =>
            
                griddata.RemoveAt(idxnum);
                griddata.Insert(idxnum, model);
            );

            Thread.Sleep(500);
        
    );


[简单演示]

我编写了一个演示项目来展示如何不断更新 UI 值,如下所示。

它使用Task启动另一个线程来更新UI值,希望对您有所帮助。

MainWindow.xaml

<Window x:Class="TestWpfApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" Title="MainWindow" Height="450" Width="800">        

    <StackPanel>
        <TextBlock Name="MyTextBlock" FontSize="20"></TextBlock>
        <Button Click="Button_Click">Start</Button>
    </StackPanel>
</Window>

MainWindow.xaml.cs

using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace TestWpfApp

    public partial class MainWindow : Window
    
        public MainWindow()
        
            InitializeComponent();
        

        private Task? CurrentTask  get; set; 

        private void Button_Click(object sender, RoutedEventArgs e)
        
            // only one task is supported simultaneously
            if (this.CurrentTask != null
                && !this.CurrentTask.IsCompleted)
            
                return;
            

            // start a task to calculate value continuously
            this.CurrentTask = Task.Run(() =>
            
                int i = 0;
                while (i < 30)
                
                    ++i;
                    Thread.Sleep(500);

                    // update value in the UI thread
                    this.Dispatcher.Invoke(() =>
                    
                        this.MyTextBlock.Text = i.ToString();
                    );
                
            );
        
    

【讨论】:

感谢您的回答。我会试试这个。 我发现这个答案最大的问题。很抱歉这个答案,文本块很好用 dispatcherDataGrid 在属性不断变化时不能很好地工作。 我更新了答案,ObservableCollection 只接受add/remove/refresh 事件。 我找到了这个article

以上是关于更改源时DataGrid更新不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用远程源时,jQuery 自动完成功能不起作用

Clarity Datagrid-尝试使用克隆对象设置选择不起作用

拖放在 DataGrid (WPF) 中不起作用

WPF - 在 DataGrid 中绑定 SolidColorBrush 不起作用

DOJO:DataGrid 增量加载不起作用

dojox.grid.DataGrid 扩展时不起作用