我有一个AccountManager
的课程Singleton class
,实现为namespace SampleApp.Manager
{
public class AccountManager : INotifyCollectionChanged, INotifyPropertyChanged
{
public static AccountManager Instance { get; } = new AccountManager();
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
private List<Account> InternalAccounts { get; } = new List<Account>();
public IReadOnlyCollection<Account> Accounts => InternalAccounts;
private AccountManager()
{
}
public void Add(Account account)
{
InternalAccounts.Add(account);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, account));
OnPropertyChanged(nameof(Accounts));
}
public void Remove(Account account)
{
if (InternalAccounts.Remove(account))
{
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, account));
OnPropertyChanged(nameof(Accounts));
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
:
Page
然后我有Account
我希望使用这些<Page x:Class="SampleApp.View.AccountView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mgr="clr-namespace:SampleApp.Manager"
mc:Ignorable="d"
d:DesignWidth="1200" d:DesignHeight="800"
Title="AccountView">
<Grid>
<TextBlock Text="{Binding Source={x:Static mgr:AccountManager.Instance}, Path=Accounts.Count}" />
<DataGrid ItemsSource="{Binding Source={x:Static mgr:AccountManager.Instance}, Path=Accounts}">
<DataGrid.Columns>
<DataGridTextColumn Header="Property1" Binding="{Binding Property1, Mode=TwoWay}" Width="*" />
<DataGridTextColumn Header="Property2" Binding="{Binding Property2, Mode=TwoWay}" Width="*" />
<DataGridTextColumn Header="Property3" Binding="{Binding Property3, Mode=TwoWay}" Width="*" />
<DataGridTextColumn Header="Property4" Binding="{Binding Property4, Mode=TwoWay}" Width="*" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Page>
个实例:
AccountManager.CollectionChanged
我首先尝试仅触发DataGrid
更新视图中的INotifyPropertyChanged
,但这没有做任何事情。接下来我实施了AccountManager.PropertyChanged
并触发了TextBlock
,但没有更新列表,只有AccountManager.Accounts
包含ObservableCollection<T>
中当前的项目数。
这只是类实际外观的简化版本,这就是为什么我不使用ObservableCollection<T>
来执行此操作的原因,所以请不要责怪我不使用{{1} }。
我想知道我的代码有什么问题?我不明白为什么DataGrid
绑定没有得到更新,但TextBlock
会更新。
答案 0 :(得分:0)
InternalAccounts
是List
,而不是ObservableCollection
。你永远不会告诉任何人你的名单改变了。在拥有它的viewmodel上实施INotifyCollectionChanged
并不能帮助List
引发任何事件:当List发生更改时,您会引发事件,说明您的viewmodel 拥有< / em>项目已更改,但实际上并没有任何项目 - 其项目位于列表中,这是XAML绑定的内容。
如果您使InternalAccounts
成为ObservableCollection
并制作Accounts
ReadOnlyObservableCollection
,那么应该修复它。
private OnlyObservableCollection<Account> _accounts =
new OnlyObservableCollection<Account>();
private ReadOnlyObservableCollection<Account> _roAccounts;
public ReadOnlyObservableCollection<Account> Accounts
{
get {
if (_roAccounts == null)
_roAccounts = new ReadOnlyObservableCollection<Account>(_accounts);
return _roAccounts;
}
}
在内部,只需添加和删除_accounts
中的内容,而不必在您的视图模型上实施INotifyCollectionChanged
。您只需免费获得完整的实施,即开即用。这比你想象的要容易得多,总是很好。