I have a datagrid that is bound to a List in the view model. The grid's contents don't update until I click on the row header. Clicking in various cells doesn't affect it. I have to click on the header.
This is the datagrid in the XAML:
<DataGrid x:Name="TransactionDetailsGrid" Grid.Row="1" AutoGenerateColumns="False" SelectionMode="Extended" IsReadOnly="True" HeadersVisibility="Column"
ItemsSource="{Binding TransactionDetailList}" SelectedItem="{Binding SelectedTransactionDetail}" GridLinesVisibility="None">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Account.AccountNumber}" Header="Account No." HeaderStyle="{StaticResource DataGridHeaderStyleCenter}" Width="120" />
<DataGridTextColumn Binding="{Binding Path=Account.AccountName}" Header="Account Name" HeaderStyle="{StaticResource DataGridHeaderStyleCenter}" Width="*" />
<DataGridTextColumn Binding="{Binding Path=Amount}" Header="Amount" HeaderStyle="{StaticResource DataGridHeaderStyleCenter}" Width="120" />
</DataGrid.Columns>
</DataGrid>
And this is from the view model:
public List<TransactionDetail> TransactionDetailList
{
get { return this._transactionDetailList; }
set
{
this._transactionDetailList = value;
RaisePropertyChanged("TransactionDetailList");
}
}
This is the edit of one of the items, in the view model:
private void AddTransactionDetail()
{
TransactionDetailViewModel viewModel = new TransactionDetailViewModel();
MainWindowViewModel.ViewLoader.ShowDialog(viewModel);
if (viewModel.TransactionDetail != null)
{
this.TransactionDetailList.Add(viewModel.TransactionDetail);
RaisePropertyChanged("TransactionDetailList");
}
}
After this runs, I can put a breakpoint on the getter of TransactionDetailList, and the collection has the item in it. However, the datagrid is empty. If I click on the header row, the item shows up in the grid.
I have the same issue when doing an edit.
I've done this successfully before, so I'm not sure what's different here. Am I missing something obvious? Why won't the grid show its contents until I click on the header row?
I just noticed something interesting. When I click on the grid header, the breakpoint in the TransactionDetailList getter doesn't get hit, but the data still shows up. So, it's like the grid has the info, it's just not showing it until the header is clicked.
After changing to use ObservableCollection, it worked. But now I'm having the same problem with the edit (grid doesn't update until clicking the header):
private void EditTransactionDetail()
{
TransactionDetailViewModel viewModel = new TransactionDetailViewModel(this.SelectedTransactionDetail);
MainWindowViewModel.ViewLoader.ShowDialog(new TransactionDetailViewModel(this.SelectedTransactionDetail));
RaisePropertyChanged("TransactionDetailList");
}
Does my entity need to implement INotifyPropertyChanged? If I change the collection, and call RaisePropertyChanged, shouldn't that cause an update to the grid?
Best Answer
The problem is that when you add or remove an item from the collection, the setter isn't called. This means
INotifyPropertyChanged
isn't called, and the view has no way of knowing it needs to be refreshed.WPF solves this by also supporting the
INotifyCollectionChanged
interface.Try using an
ObservableCollection<TransactionDetail>
instead of aList<TransactionDetail>
.ObservableCollection<T>
is built in, and implementsINotifyCollectionChanged
, so you won't have to do much to your code.Also make sure that you continue to implement
INotifyPropertyChanged
on your view model as you already have. This way the view will be notified when you replace the entire collection (when the setter is called).See:
Edit:
Also, you should implement
INotifyPropertyChanged
onTransactionDetail
too. If you can't, wrap it in a class that does implementINotifyPropertyChanged
.If you don't implement it on
TransactionDetail
, than changes you make that don't impact the list, but do impact properties on aTransactionDetail
instance, won't show in the UI until you somehow refresh the whole list.If you tried to fix this by calling
RaisePropertyChanged
on the list property, then your UI thinks the entire list (and hence the whole set of UI objects) needs to be thrown out and updated. This will kill your performance and make your app sluggish.