This is my DataGrid testing code. I set some data on the DataGrid source with ObservableCollection and bound this. And I modify the value where the ObservableCollection member's property. In this case, my UI has to show that value is changed. However, my DataGrid only interact when I selected the cell.
Binding
public ObservableCollection<MyClass> griddata { get; set; } = new ObservableCollection<MyClass>();
My Class
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>
Function
//... 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;
}
Result
Cell value shows that 0
and I selected value is changed to 30
, immediately.
Expect result
Cell value shows 0
to 30
continuously.
EDIT :
This is my whole code:
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);
}
}
}
}
CodePudding user response:
Try implementing INotifyPropertyChanged in your model
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));
}
}
}
CodePudding user response:
[Solution]
In WPF, you can get dispatcher
from Application.Current.Dispatcher
How to pass the UI Dispatcher to the ViewModel
And we need to change items in ObservableCollection
to notify value change events.
The document of ObservableCollection
says:
Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
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);
}
});
}
[Simple Demo]
I wrote a demo project to show how to update UI value continuously as below.
It use Task
to start another thread to update UI value, hope it helps.
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();
});
}
});
}
}
}