Reputation: 59
What should I do to make the WPF DataGrid display changes in its ObservableCollection's items when they are changed in code?
<DataGrid HorizontalAlignment="Left" Height="100" Margin="54,25,0,0" VerticalAlignment="Top" Width="264"
IsSynchronizedWithCurrentItem="True" AutoGenerateColumns="False"
ItemsSource="{Binding DataSource}" SelectedItem="{Binding SelectedPerson}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding FirstName}" />
<DataGridTextColumn Binding="{Binding LastName}" />
</DataGrid.Columns>
</DataGrid>
I update SelectedPerson.FirstName
in code and the setter of DataSource
executes. The current DataSource.FirstName
has been updated but the DataGrid does not display the change. If I click on a column header the DataGrid refreshes and shows the changed data. How can I make it refresh promptly when I am using MVVM and I don't have a reference to the DataGrid?
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class VM : Notifier
{
private ObservableCollection<Person> dataSource;
public ObservableCollection<Person> DataSource
{
get { return dataSource; }
set
{
dataSource = value;
OnPropertyChanged("DataSource");
}
}
private Person selectedPerson;
public Person SelectedPerson
{
get { return selectedPerson; }
set
{
selectedPerson = value;
OnPropertyChanged("SelectedPerson");
}
}
private string string1;
public string String1
{
get { return string1; }
set
{
string1 = value;
OnPropertyChanged(String1);
}
}
public VM()
{
String1 = "abc";
DataSource = new ObservableCollection<Person>();
DataSource.Add(new Person { FirstName = "Alpha", LastName = "Apple" });
DataSource.Add(new Person { FirstName = "Beta", LastName = "Banana" });
DataSource.Add(new Person { FirstName = "Charlie", LastName = "Cucumber" });
}
public ICommand SetSelectedCommand => new RelayCommandBase(SetSelected);
private void SetSelected(object parameter = null)
{
SelectedPerson.FirstName = String1;
SelectedPerson = SelectedPerson; // force setter to run
DataSource = DataSource; // force ObservableCollection setter to run
}
}
Upvotes: 0
Views: 4501
Reputation: 142
Your changes are not getting reflected as the item that is getting updated (Person) DOES NOT raise change notifications to update the UI. To do so, you need to update the Person class to Implement the interface INotifyPropertyChanged in the class Person, the same way you implemented in the viewmodel, and this should work.
public class Person:Notifier
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged(nameof(this.FirstName));
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
OnPropertyChanged(nameof(this.LastName));
}
}
}
One more thing. If supported in your version of .NET Framework, you can use the C# nameof to get the property name in string instead of hard-coding the name. This helps when you refactor/rename the properties.
Upvotes: 0
Reputation: 169400
The Person
class should implement the INotifyPropertyChanged interface:
public class Person : INotifyPropertyChanged
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
NotifyPropertyChanged();
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Upvotes: 2