2013-07-18 8 views
11

C'è un modo per aggiornare automaticamente un filtro su un ICollectionView senza dover chiamare Refresh() quando è stata apportata una modifica rilevante?Aggiorna automaticamente il filtro ICollectionView

Ho il seguente:

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

Il [Notifica] attributo in questa proprietà implementa solo INotifyPropertyChanged, ma non sembra essere di fare qualsiasi cosa in questa situazione.

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}" /> 

Aggiornamento: Sembra utilizzando ICollectionView sta per essere necessario per me, quindi mi piacerebbe rivisitare questo argomento. Aggiungo una generosità a questa domanda, il cui destinatario sarà qualsiasi persona in grado di fornire alcune informazioni su come implementare un 'hands-off' ICollectionView che non necessita di essere aggiornato manualmente. A questo punto sono aperto a qualsiasi idea.

+0

Beh, considerando che l'attributo non è BCL, non è sorprendente che non copre questo caso angolo. In realtà, non c'è nulla in WPF che copra questo caso, quindi dovrai farlo tu stesso. La proprietà filter non è un DP, e anche lo era, nulla nel filtro attiverebbe un evento di aggiornamento. Sembra che dovrai attivarlo manualmente. Forse nel corpo del filtro? Puoi fare riferimento personale tramite la chiusura. Guardando il lambda, dovresti scaricare la chiamata in Refresh su Dispatcher, in modo che si avvii dopo l'applicazione del filtro. Ergh, e aggiungi un blocco bool "aggiornamento brb" – Will

+0

(non più caratteri) sembra che non ci sia alcun modo per aggirarlo, eccetto forse per l'estensione del CVS e l'aggiornamento durante un filtro, con controlli per essere sicuro di non attivarlo continuamente un aggiornamento. Ha senso perché non è BCL, giusto? Il filtro attiva un aggiornamento, che attiva un filtro e così via ... – Will

+0

Grazie per la spiegazione. Sembra che lo farò manualmente. –

risposta

13

AFAIK non è presente un supporto integrato in ICollectionView per aggiornare la raccolta su qualsiasi modifica di proprietà nella raccolta di origine sottostante.

Ma è possibile creare una sottoclasse di ListCollectionView per assegnare la propria implementazione a refresh collection on any property changed. Esempio -

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

È possibile utilizzare questo nel progetto come questo -

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

Questo può essere riutilizzato in tutto il progetto, senza doversi preoccupare di aggiornare la raccolta su ogni PropertyChanged.MyCollectionView lo faranno per voi automatically.

O

Se si utilizza .Net4.5 si può andare con ICollectionViewLiveShaping implementazione come descritto here.

Ho pubblicato la parte di implementazione per il tuo problema qui - Implementing ICollectionViewLiveShaping.

codice di lavoro da quella post -

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

L'approccio della sottoclasse funziona perfettamente! Grazie! –

+0

Beh, una specie di. Quando un nuovo elemento viene aggiunto alla raccolta, non viene gestito correttamente poiché la logica è nel costruttore. Ci giocherò un po 'e vedrò cosa posso fare. –

+1

In realtà, anche questa implementazione di 'ICollectionViewLiveShaping' funziona. Non so cosa ho sbagliato all'inizio quando ho provato la tua risposta. Grazie ancora! –

8

Per .Net 4.5: C'è una nuova interfaccia diche può aiutare a raggiungere questa funzione, denominata: ICollectionViewLiveShaping.

Da MSDN link:

Quando vivo ordinamento, raggruppamento o il filtraggio viene attivato, un CollectionView si risistemare dati nel CollectionView quando i dati viene modificato. Ad esempio, supponiamo che un'applicazione utilizzi un DataGrid per elencare gli stock in un mercato azionario e che le scorte siano ordinate per il valore dello stock . Se l'ordinamento live è abilitato sul CollectionView degli stock, , la posizione di un titolo nel DataGrid si sposta quando il valore dello stock diventa maggiore o minore del valore di un altro grezzo.

più informazioni interfaccia di cui sopra: http://www.jonathanantoine.com/2011/10/05/wpf-4-5-%E2%80%93-part-10-live-shaping/


Per .Net 4 e inferiore: C'è anche un altro post su SO QA che potrebbe aiutare: CollectionViewSource Filter not refreshed when Source is changed

+0

Se puoi aiutarmi a farlo funzionare, la ricompensa ti andrà sicuramente. Ho postato una domanda sull'implementazione di 'ICollectionViewLiveShaping' qui: http://stackoverflow.com/questions/17865202/implementing-icollectionviewliveshaping –