更改源时,DataGrid更新不起作用



这是我的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>

型号.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);
}
}
}
}

尝试在模型中实现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));
}
}
}

[解决方案]

在WPF中,您可以从Application.Current.Dispatcher中获取dispatcher

如何将UI Dispatcher传递给ViewModel

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

ObservableCollection的文件上写着:

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

https://learn.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值,希望它能有所帮助。

主窗口.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>

主窗口.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();
});
}
});
}
}
}

最新更新