Modular Filter Architecture per WPF

6

Sto creando un piccolo strumento di gestione delle scorte per uso privato.

Ho diverse visualizzazioni, che richiedono filtri simili ma diversi. Ad esempio, ho un elenco di "scorte correnti" in cui posso filtrare per fornitore, gruppo di prodotti e nome. Ho di nuovo la stessa lista ma con filtri aggiuntivi per alcune bandiere booleane. Creerò una piccola vista statistica in cui avrò bisogno di tutti i filtri citati e di un intervallo di date più simile.

Un ultimo, ma non meno importante, sto creando una piccola esportazione csv in cui ho requisiti simili a quelli della vista statistica.

Non è molto, ma abbastanza da pensare a un'architettura decente. Se lo fai bene su piccola scala, è probabile che lo faccia nei progetti più grandi.

Uso WPF con MVVM.
Finora ho pensato ad alcuni modi per affrontare il mio problema:

  1. Filtro individuale per ogni vista: è ovviamente la variante più flessibile, ma comporta anche il massimo del lavoro se viene modificato qualcosa riguardante i filtri.

  2. Generatore di filtri: un controllo viene generato in base alla configurazione, suona bene ma ho perso la flessibilità dello styling del filtro in base alla vista (potrei aggiungerlo alla configurazione, ma mi perderebbero comunque i vantaggi di xaml) e non posso davvero visualizzarlo in anteprima in xaml durante la progettazione.

  3. Creazione di un singolo ViewModel che contiene tutti i possibili filtri e controlli + ViewModels per ogni tipo di filtro (Checkbox, Combobox, Textbox). Questo approccio permetterebbe semplicemente di modellare il filtro in xaml usando i controlli del filtro per ogni vista mentre si assorbe la VM del filtro in un'implementazione.

Per me l'opzione 3. sembra preferibile, ma come non ho mai fatto nulla allo stesso modo, quindi sto cercando un feedback su come un tale problema viene solitamente affrontato o se esiste qualche schema correlato.

    
posta lolsharp 09.10.2015 - 16:42
fonte

3 risposte

1

Vorrei utilizzare MVVM completo per questa soluzione.

  • Il modello Filter e le sottoclassi (ad esempio XYZFilter ) controllano come applicare il filtro ai dati e possono essere facilmente testati
  • XYZFilterViewModel si prende cura di eventuali esigenze di bridging dell'interfaccia utente
  • XYZFilterView si prende cura dell'interfaccia utente stessa

Ciò consente di riutilizzare i filtri su tutti gli schermi. Indipendentemente dal codice Visualizza prima o ViewModel, gli stessi meccanismi utilizzati per l'intera pagina possono funzionare per piccoli pezzi della pagina. Questo è un esempio perfetto in cui puoi farlo facilmente. Riutilizzando le singole visualizzazioni e i modelli di visualizzazione, si garantisce anche un'esperienza utente coerente per tutta l'applicazione.

Per quanto riguarda la seconda opzione, avere XAML personalizzato per ogni pagina può presentare un'esperienza negativa all'utente. Quando gli utenti vedono gli stessi controlli su pagine diverse, la loro sicurezza aumenta poiché sanno che devono solo imparare il controllo una volta.

Ho davvero difficoltà a capire cosa intendi nella tua terza opzione. Stai parlando di un ViewModel che contiene proprietà per tutti i filtri nella tua applicazione? Come funzionerebbe l'aggiunta o la rimozione dei filtri? Mi sento come se mi mancasse qualcosa perché suona come un incubo di manutenzione.

    
risposta data 05.09.2017 - 20:47
fonte
0

Vorrei iniziare determinando i tipi di raccolta da utilizzare nell'intera applicazione, cercando di mantenere solo una raccolta di dati "Maggiori" laddove possibile.

Da lì quando viene impostata la nuova raccolta "Major", può attivare un evento per qualsiasi listener che può mostrare una vista diversa. (Gli eventi sono uno schema di Osservatore). Ogni osservatore ha quindi l'indirizzabilità alla collezione "Major" e può racchiuderlo con una CollectionViewSource che consente un'eccellente capacità di filtraggio. Ogni vista ha requisiti di filtraggio diversi. Il filtro per altre visualizzazioni avviene solo quando tale visualizzazione riceve lo stato attivo.

Ogni vista può quindi aggiungere colonne alla vista o nascondere colonne non necessarie.

Ci sono trucchi per questo in cui è possibile utilizzare le funzioni in un metodo per consentire il filtraggio di una griglia basata su ciò che "un chiamante" per determinare cosa è necessario filtrare. Tutto il filtro può quindi essere estratto dal file app.config in modo che i nuovi filtri dinamici possano essere aggiunti a piacimento in base ai valori che l'utente inserisce nel file di configurazione, questo consente un nuovo comportamento senza ricompilare i progetti.

Da lì, man mano che l'applicazione cresce, potresti voler aggiungere un livello "repository" che praticamente sposta tutti gli accessi ai dati e la logica aziendale in un unico posto una volta sola. Quindi tutte le viste chiamerebbero semplicemente le funzioni 'repository' per ottenere tutto ciò di cui hanno bisogno.

L'uso di oggetti LINQ e CollectionViewSource associati a datagrids è una delle migliori combinazioni di strumenti disponibili. In aggiunta, ove possibile, mi piace molto anche Entity Framework, se il back-end è SQL. Se hai a che fare con JSON, allora JSON.NET è lo strumento migliore per questo.

    
risposta data 15.10.2015 - 15:40
fonte
0

Crea le "unità filtro" più piccole.

Checkbox        -> BooleanFilterViewModel  -> BooleanFilter   
DatePicker      -> DateTimeFilterViewModel -> DateTimeFilter  
(Two textboxes) -> IntegerRangeViewModel   -> IntegerRange  

Quindi puoi creare diverse viste combinando tutti i filtri insieme.
Rimarrà flessibile, perché hai l'unità più piccola che può essere aggiunta, rimossa, sostituita

Se possibile, introduci astrazioni invece di tipi concreti per viewmodels e filtri

IDateTimeFilterViewModel
IIntegerRangeFilterViewModel

IDateTimeFilter
IIntegerRangeFilter

Le astrazioni ti danno la possibilità di riutilizzare gli stessi filtri viewmodels / views che hanno un comportamento diverso.

Ad esempio

public class TodayStockViewModel
{
    public IIntegerRangeFilterViewModel PriceFilter { get; set; }
    public IDateTimeFilterViewModel TimeFilter { get; set; }
    public IBooleanFilterViewModel OnlyDomesticCompaniesFilter { get; set; }
}
    
risposta data 04.04.2018 - 02:43
fonte

Leggi altre domande sui tag