I have a class AccountManager
that is implemented as a 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));
}
}
}
Then I have Page
where I want to work with these Account
instances:
<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>
I first tried to only trigger AccountManager.CollectionChanged
to update the DataGrid
in the view but that did nothing. So next I implemented INotifyPropertyChanged
and triggered AccountManager.PropertyChanged
but that did not update the list but only the TextBlock
containing the current number of items in AccountManager.Accounts
.
This is just a stripped down version of what the classes actually look like so that's the reason why I don't use ObservableCollection<T>
to do this, so please don't blame me for not using ObservableCollection<T>
.
I would like to know what's wrong with my code? I don't understand why the DataGrid
binding isn't getting updated but the TextBlock
gets updated.
InternalAccounts
is a List
, not an ObservableCollection
. You never tell anybody that your list changed. Implementing INotifyCollectionChanged
on the viewmodel that owns it doesn't help the List
raise any events: When the List changes, you do raise events saying that your viewmodel's own items changed, but it doesn't actually have any items -- its items are in the list, which is what the XAML is bound to.
If you make InternalAccounts
an ObservableCollection
and make Accounts
ReadOnlyObservableCollection
, that should fix it.
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;
}
}
Internally, just add and remove stuff from _accounts
and don't bother implementing INotifyCollectionChanged
on your viewmodel. You just got a full implementation for free, out of the box. This is much easier to do than you thought, which is always nice.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.