2013-07-18 4 views
11

Gibt es eine Möglichkeit, einen Filter auf einer ICollectionView automatisch zu aktualisieren, ohne Refresh() aufrufen zu müssen, wenn eine relevante Änderung vorgenommen wurde?ICollectionView-Filter automatisch aktualisieren

Ich habe folgendes:

[Notify] 
public ICollectionView Workers { get; set; } 

Die [Benachrichtigen] Attribut in dieser Eigenschaft nur implementiert INotifyPropertyChanged aber es scheint nicht in dieser Situation etwas zu tun zu sein.

Workers = new CollectionViewSource { Source = DataManager.Data.Workers }.View; 

Workers.Filter = w => 
    { 
     Worker worker = w as Worker; 
     if (w == null) 
      return false; 
     return worker.Employer == this; 
    }; 

In XAML:

<TextBlock x:Name="WorkersTextBlock" 
      DataContext="{Binding PlayerGuild}" 
      FontFamily="Pericles" 
      Text="{Binding Workers.Count, 
          StringFormat=Workers : {0}, 
          FallbackValue=Workers : 99}" /> 

Update: Es sieht aus wie mit ICollectionView für mich notwendig sein wird, so möchte ich dieses Thema zu überdenken. Ich füge ein Kopfgeld zu dieser Frage hinzu, deren Empfänger jede Person sein wird, die einen Einblick geben kann, wie man einen "Hands-Off" ICollectionView implementiert, der nicht manuell aktualisiert werden muss. An dieser Stelle bin ich für alle Ideen offen.

+0

Nun, ist dieses Attribut nicht unter Berücksichtigung BCL, ist es nicht verwunderlich, dass es nicht diese Ecke Fall abdeckt. Tatsächlich gibt es in WPF nichts, was diesen Fall abdeckt, also müssen Sie es selbst tun. Die Filtereigenschaft ist kein DP und selbst wenn dies der Fall wäre, würde nichts im Filter ein Aktualisierungsereignis auslösen. Sieht so aus, als müssten Sie es manuell auslösen. Vielleicht im Körper des Filters? Sie können sich über den Verschluss selbst beziehen. Wenn Sie sich das Lambda ansehen, müssen Sie den Aufruf von Aktualisieren an den Dispatcher auslagern, damit er ausgeführt wird, nachdem der Filter angewendet wurde. Ergh, und fügen Sie einen bool "brb update" Block – Will

+0

(keine Zeichen mehr) sieht aus als gäbe es keinen Weg, außer vielleicht CVS und Updates während eines Filters zu erweitern, mit Überprüfungen, um sicherzustellen, dass Sie nicht kontinuierlich auslösen ein Update. Macht Sinn, warum das nicht BCL ist, oder? Filter löst ein Update aus, das einen Filter auslöst, und so weiter und so weiter ... – Will

+0

Danke für die Erklärung. Es sieht so aus als würde ich das manuell machen. –

Antwort

13

AFAIK gibt es keine integrierte Unterstützung in ICollectionView, um die Auflistung für alle Eigenschaftenänderungen in der zugrunde liegenden Quellensammlung zu aktualisieren.

Sie können jedoch ListCollectionView von der Unterklasse refresh collection on any property changed ableiten. Probe -

public class MyCollectionView : ListCollectionView 
{ 
    public MyCollectionView(IList sourceCollection) : base(sourceCollection) 
    { 
     foreach (var item in sourceCollection) 
     { 
      if (item is INotifyPropertyChanged) 
      { 
       ((INotifyPropertyChanged)item).PropertyChanged += 
                (s, e) => Refresh(); 
      } 
     } 
    } 
} 

Sie können dies wie folgt in Ihrem Projekt verwenden -

Workers = new MyCollectionView(DataManager.Data.Workers); 

Dies kann Sammlung kümmern, ohne dass in Ihrem Projekt wiederverwendet werden aufzufrischen auf jedem PropertyChanged.MyCollectionView wird das automatically für Sie tun.

ODER

Wenn Sie mit .Net4.5 Sie mit ICollectionViewLiveShaping Umsetzung gehen kann als here beschrieben.

Ich habe den Implementierungsteil für Ihr Problem hier - Implementing ICollectionViewLiveShaping.

Arbeits Code aus diesem Posten -

public ICollectionViewLiveShaping WorkersEmployed { get; set; } 

ICollectionView workersCV = new CollectionViewSource 
         { Source = GameContainer.Game.Workers }.View; 

ApplyFilter(workersCV); 

WorkersEmployed = workersCV as ICollectionViewLiveShaping; 
if (WorkersEmployed.CanChangeLiveFiltering) 
{ 
    WorkersEmployed.LiveFilteringProperties.Add("EmployerID"); 
    WorkersEmployed.IsLiveFiltering = true; 
} 
+0

Der Ansatz der Unterklasse funktioniert perfekt! Vielen Dank! –

+0

Nun, irgendwie. Wenn ein neues Element zur Sammlung hinzugefügt wird, wird es nicht richtig behandelt, da sich die Logik im Konstruktor befindet. Ich werde etwas damit herumspielen und schauen, was ich tun kann. –

+1

Tatsächlich funktioniert diese Implementierung von 'ICollectionViewLiveShaping' auch. Ich weiß nicht, was ich zuerst falsch gemacht habe, als ich deine Antwort versucht habe. Danke noch einmal! –

8

Für .Net 4.5: Es gibt eine neue Schnittstelle, die diese Funktion erreichen helfen können, genannt: ICollectionViewLiveShaping.

Von MSDN link:

Wenn Live-Sortieren, Gruppieren oder Filterung freigegeben ist, ein Collection wird die Position der Daten in der neu anzuordnen, wenn die Collection Daten modifiziert wird. Angenommen, eine Anwendung verwendet ein DataGrid , um Aktien an einer Börse aufzulisten, und die Aktien werden nach Aktienwert sortiert. Wenn die Live-Sortierung für das CollectionView der Bestände aktiviert ist, wird die Position eines Bestands im DataGrid verschoben, wenn der Wert des Bestands größer oder kleiner als der Wert eines anderen Bestands wird.

Mehr Infos auf über Schnittstelle: http://www.jonathanantoine.com/2011/10/05/wpf-4-5-%E2%80%93-part-10-live-shaping/


Für .Net 4 und geringere: auf SO QA ein weiterer Beitrag Es gibt auch die Ihnen helfen könnten: CollectionViewSource Filter not refreshed when Source is changed

+0

Wenn Sie mir helfen können, das funktioniert, wird die Prämie sicherlich zu Ihnen gehen. Ich habe eine Frage über die Implementierung von 'ICollectionViewLiveShaping' hier gestellt: http://stackoverflow.com/questions/17865202/implementing-icollectionviewliveshaping –