我有一个绑定到视图模型中List的数据网格。在单击行标题之前,网格的内容不会更新。单击各种单元格不会影响它。我必须点击标题。
这是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>
这是来自视图模型:
public List<TransactionDetail> TransactionDetailList
{
get { return this._transactionDetailList; }
set
{
this._transactionDetailList = value;
RaisePropertyChanged("TransactionDetailList");
}
}
这是视图模型中其中一个项目的编辑:
private void AddTransactionDetail()
{
TransactionDetailViewModel viewModel = new TransactionDetailViewModel();
MainWindowViewModel.ViewLoader.ShowDialog(viewModel);
if (viewModel.TransactionDetail != null)
{
this.TransactionDetailList.Add(viewModel.TransactionDetail);
RaisePropertyChanged("TransactionDetailList");
}
}
运行之后,我可以在TransactionDetailList的getter上放置一个断点,并且该集合中包含该项。但是,datagrid是空的。如果我单击标题行,该项目将显示在网格中。
进行编辑时遇到同样的问题。
我以前成功完成了这个,所以我不确定这里有什么不同。我错过了一些明显的东西吗为什么在我点击标题行之前网格不会显示其内容?
我刚注意到一些有趣的事情。当我单击网格标题时,TransactionDetailList getter中的断点不会被点击,但数据仍会显示。所以,它就像网格有信息一样,只是在点击标题之后才显示它。
更改为使用ObservableCollection后,它工作正常。但是现在我在编辑时遇到了同样的问题(网格在点击标题之前不会更新):
private void EditTransactionDetail()
{
TransactionDetailViewModel viewModel = new TransactionDetailViewModel(this.SelectedTransactionDetail);
MainWindowViewModel.ViewLoader.ShowDialog(new TransactionDetailViewModel(this.SelectedTransactionDetail));
RaisePropertyChanged("TransactionDetailList");
}
我的实体是否需要实施INotifyPropertyChanged?如果我更改了集合并调用了RaisePropertyChanged,那么这不应该导致对网格的更新吗?
答案 0 :(得分:10)
问题是,当您从集合中添加或删除项目时,不会调用setter。这意味着不会调用INotifyPropertyChanged
,并且视图无法知道它需要刷新。
WPF通过支持INotifyCollectionChanged
接口来解决这个问题。
尝试使用ObservableCollection<TransactionDetail>
代替List<TransactionDetail>
。 ObservableCollection<T>
是内置的,并且实现了INotifyCollectionChanged
,因此您无需为代码做太多工作。
另外,请确保您已经在视图模型上继续实施INotifyPropertyChanged
。这样,当您替换整个集合时(通知调用setter时)将通知视图。
public ObservableCollection<TransactionDetail> TransactionDetailList
{
get { return this._transactionDetailList; }
set
{
this._transactionDetailList = value;
RaisePropertyChanged("TransactionDetailList");
}
}
请参阅:
修改强>:
此外,您还应在INotifyPropertyChanged
上实施TransactionDetail
。如果不能,请将其包装在实现INotifyPropertyChanged
的类中。
如果您未在TransactionDetail
上实施,那么您所做的更改不会影响列表,但影响TransactionDetail
实例上的属性,则不会在用户界面中显示你以某种方式刷新整个清单。
如果您尝试通过调用list属性上的RaisePropertyChanged
来解决此问题,那么您的UI会认为需要抛出并更新整个列表(以及整个UI对象集)。这会扼杀你的表现并使你的应用程序变得迟钝。
答案 1 :(得分:2)
如果您希望网格在更改绑定的IEnumerable列表时更新,请将其作为一种实现INotifyCollectionChanged的列表。具有此内置数据类型的是ObservableCollection(also here)。所以如果你让你的财产看起来像这样:
public ObservableCollection<TransactionDetail> TransactionDetailList
{
get { return this._transactionDetailList; }
set
{
this._transactionDetailList = value;
RaisePropertyChanged("TransactionDetailList");
}
}
您的网格会自动获取您在列表中添加或删除的所有项目 实际上,您在此处所做的是在列表发生更改时通知(即列表引用),但是当列表的内容发生更改时您没有通知。