这是我的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
。
预期结果
单元格值连续显示0
到30
。
编辑:
这是我的全部代码:
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();
});
}
});
}
}
}