2016-07-29 14 views
0

verändert Ich habe eine Klasse AccountManager, die als Singleton class implementiert:Datagrid nicht aktualisiert, wenn Itemssource

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)); 
     } 
    } 
} 

Dann habe ich Page wo ich mit diesen Account Instanzen arbeiten wollen:

<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 zuerst versucht, nur AccountManager.CollectionChanged zu triggern, um die DataGrid in der Ansicht zu aktualisieren, aber das tat nichts. Als nächstes implementierte ich INotifyPropertyChanged und löste AccountManager.PropertyChanged aus, aber das aktualisierte nicht die Liste, sondern nur die TextBlock, die die aktuelle Anzahl der Elemente in AccountManager.Accounts enthält.

Dies ist nur eine abgespeckte Version von dem, was die Klassen tatsächlich aussehen, deshalb ist das der Grund, warum ich ObservableCollection<T> dafür nicht verwende, also bitte tadeln Sie mich nicht, ObservableCollection<T> zu verwenden.

Ich möchte wissen, was mit meinem Code falsch ist? Ich verstehe nicht, warum die DataGrid Bindung nicht aktualisiert wird, aber die TextBlock wird aktualisiert.

Antwort

0

InternalAccounts ist ein List, kein ObservableCollection. Sie sagen niemandem, dass sich Ihre Liste geändert hat. Die Implementierung von INotifyCollectionChanged auf dem Viewmodel, das es besitzt, hilft dem List nicht, alle Ereignisse zu erhöhen: Wenn die Liste sich ändert, erhöhen Sie Ereignisse, die eigene Elemente Ihres Viewmodells ändern, aber es hat tatsächlich keine Elemente - seine Elemente sind in der Liste, an die der XAML gebunden ist.

Wenn Sie InternalAccounts eine ObservableCollection und machen AccountsReadOnlyObservableCollection, das sollte es beheben.

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; 
    } 
} 

Intern nur hinzufügen und Sachen aus _accounts entfernen und nicht der Mühe INotifyCollectionChanged auf Ihrem Viewmodel zu implementieren. Sie haben jetzt eine vollständige Implementierung kostenlos, out of the box. Das ist viel einfacher zu machen, als Sie dachten, was immer nett ist.