Domanda

Sto usando WPF, e il tentativo di seguire il modello MVVM. Il nostro team ha deciso di utilizzare il controllo Xceed DataGrid, e sto avendo qualche difficoltà a farla inserire nel modello MVVM.

Un requisito che devo incontrare è che ho bisogno di sapere quando un utente modifica un filtro di colonna sulla griglia. Sono consapevole del fatto che la versione più recente del controllo DataGrid è un evento che viene generato per questo, ma purtroppo, devo usare una versione precedente del controllo.

Dopo aver cercato per un po ', ho trovato questo post . Si dice che ho bisogno di collegare un gestore INotifyCollectionChanged a ciascuna delle possibili elenco dei filtri. Questo funziona, ma si dice anche che ho bisogno di sganciare i gestori ogni volta che l'origine riga dei cambiamenti della griglia.

sono stato in grado di farlo al lavoro quando ho impostato in modo esplicito che l'origine riga nel codebehind della pagina (e nel mio primo tentativo in modelview utilizzando un riferimento diretto alla vista gasp! )

Il primo problema che mi imbatto in però, è come fare questo senza avere la logica nel codice dietro o nel ViewModel. La mia soluzione era quella di estendere la classe DataGridControl e di aggiungere il seguente codice:

    private IDictionary<string, IList> _GridFilters = null;
    public MyDataGridControl() : base()
    {
        TypeDescriptor.GetProperties(typeof(MyDataGridControl))["ItemsSource"].AddValueChanged(this, new EventHandler(ItemsSourceChanged));
    }

    void ItemsSourceChanged(object sender, EventArgs e)
    {
        UnsetGridFilterChangedEvent();
        SetGridFilterChangedEvent();
    }

    public void SetGridFilterChangedEvent()
    {
        if (this.ItemsSource == null)
            return;

        DataGridCollectionView dataGridCollectionView = (DataGridCollectionView)this.ItemsSource;

        _GridFilters = dataGridCollectionView.AutoFilterValues;

        foreach (IList autofilterValues in _GridFilters.Values)
        {
            ((INotifyCollectionChanged)autofilterValues).CollectionChanged += FilterChanged;
        }
    }

    /*TODO: Possible memory leak*/
    public void UnsetGridFilterChangedEvent()
    {
        if (_GridFilters == null)
            return;

        foreach (IList autofilterValues in _GridFilters.Values)
        {
            INotifyCollectionChanged notifyCollectionChanged = autofilterValues as INotifyCollectionChanged;

            notifyCollectionChanged.CollectionChanged -= FilterChanged;
        }

        _GridFilters = null;
    }

Questo mi ha portato al mio prossimo problema; Sono abbastanza sicuro che per il momento il metodo ItemsSourceChanged viene chiamato, la raccolta di AutoFilterValues ??ha già cambiato, quindi non posso sganciare in modo efficace i gestori.

Ho ragione nel ritenere questo? E qualcuno può pensare a un modo migliore di gestire questi gestori, mentre ancora mi permette di mantenere tale funzionalità incapsulata all'interno della mia classe estesa?

Ci scusiamo per la lunghezza del post, e grazie in anticipo per l'aiuto!

-Funger

È stato utile?

Soluzione

Lei ha ragione che AutoFilterValues ??avranno già cambiato a quel punto, in modo da essere sganciando i gestori sbagliate, con un conseguente perdita di memoria.

La soluzione è molto semplice. Fare esattamente quello che stai facendo, ma utilizza un List<IList> invece di AutoFilterValues ??solo riferimento a:

private List<IList> _GridFilters;

e l'uso ToList() per fare una copia dei filtri imposti gestori su:

_GridFilters = dataGridCollectionView.AutoFilterValues.Values.ToList();

Dal _GridFilters è ora un List<IList>, avrete anche di modificare i cicli:

foreach(IList autofilterValues in _GridFilters) 
  ...

Il motivo per cui funziona è che ha l'elenco dei vecchi elenchi di filtri viene copiato in _GridFilters, piuttosto che semplicemente riferimento alla proprietà AutoFilterValues.

Questa è una bella tecnica generale che è applicabile in molte situazioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top