Frage

Ich bin mit WPF, und versuchen, das MVVM Muster zu folgen. Unser Team hat beschlossen, die Xceed Datagrid-Steuerelement zu verwenden, und ich habe einige Schwierigkeiten bekommen es in das MVVM Muster passen.

Eine Anforderung, dass ich zu treffen habe, ist, dass ich wissen muß, wenn ein Benutzer einen Spaltenfilter auf dem Gitter ändert. Ich bin mir bewusst, dass die neueste Version des Datagrid-Steuerelement ein Ereignis hat, die für diese erhöht wird, aber leider, ich habe eine ältere Version der Steuerung verwenden.

Nach einer Weile suchen, fand ich diese Post. Er sagt, dass ich einen INotifyCollectionChanged Handler zu jedem der möglichen Liste der Filter anschließen muß. Dies funktioniert, aber es sagt auch, dass ich die Handler aushängen müssen, wenn die Zeilenquelle der Raster Änderungen.

Ich konnte es an der Arbeit machen, wenn ich die Zeile Quelle in dem Code-Behind der Seite explizit festgelegt (und in meinem ersten Versuch in der Modelview einen direkten Bezug auf die Ansicht mit Keuchen! )

Das erste Problem, dass ich in obwohl laufe, ist, wie dies ohne zu tun, hinter der Logik in dem Code mit oder im Ansichtsmodell. Meine Lösung war die DataGridControl Klasse zu erweitern und den folgenden Code hinzuzufügen:

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

Dies führt mich zu meinem nächsten Problem; Ich bin mir ziemlich sicher, dass die ItemsSourceChanged Methode durch die Zeit genannt wird, hat sich die Sammlung von AutoFilterValues ??bereits geändert, so kann ich nicht effektiv die Handler aushängen.

rechts Bin ich dies in der Annahme? Und kann jemand denken Sie an einen besseren Weg, diese Handler verwalten, während immer noch mir erlaubt diese Funktionalität in meiner erweiterten Klasse eingekapselt zu halten?

Sorry über die Länge der Post, und Dank im Voraus für die Hilfe!

-Funger

War es hilfreich?

Lösung

Sie sind richtig, dass AutoFilterValues ??wird bereits an diesem Punkt geändert hat, so dass Sie die falschen Handler Aushänge werden, was zu einem Speicherverlust.

Die Lösung ist sehr einfach. Genau das tun, was Sie tun, aber eine List<IList> statt nur Referenzierung AutoFilterValues ??verwenden:

private List<IList> _GridFilters;

und Verwendung ToList() eine Kopie der Filter zu machen setzen Sie Handler auf:

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

Da _GridFilters nun ein List<IList>, werden Sie auch die Schleifen ändern müssen:

foreach(IList autofilterValues in _GridFilters) 
  ...

Der Grund dieser Arbeiten ist, dass die aktuelle Liste der alten Filterlisten in _GridFilters kopiert wird, anstatt einfach Referenzierung der AutoFilterValues ??Eigenschaft.

Dies ist eine nette allgemeine Technik, die in vielen Situationen anwendbar ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top