Pregunta

Estoy usando WPF, y tratar de seguir el patrón MVVM. Nuestro equipo ha decidido utilizar el control Xceed DataGrid, y estoy teniendo algunas dificultades para conseguir que encajar en el patrón MVVM.

Uno de los requisitos que tienen que cumplir es que necesito saber cuando un usuario cambia un filtro de columna en la parrilla. Soy consciente de que la última versión del control DataGrid tiene un evento que se establezca para esto, pero por desgracia, tengo que utilizar una versión anterior del control.

Después de buscar durante un rato, me encontré este post . Se dice que necesito para conectar un controlador INotifyCollectionChanged a cada una de la posible lista de filtros. Esto funciona, pero también dice que necesito para desenganchar los manipuladores siempre que el origen de la fila de los cambios en la rejilla.

Yo era capaz de conseguir que funcione cuando me puse explícitamente el origen de la fila en el código subyacente de la página (y en mi primer intento en el modelview usando una referencia directa a la vista jadeo! )

El primer problema que me encuentro, sin embargo, es cómo hacer esto sin tener la lógica en el código detrás o en el modelo de vista. Mi solución fue la de extender la clase DataGridControl y añadir el siguiente código:

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

Esto me lleva a mi siguiente problema; Estoy bastante seguro de que por el momento el método ItemsSourceChanged se llama, la colección de AutoFilterValues ??ya ha cambiado, así que no puedo desenganchar de manera efectiva los controladores.

Estoy en lo cierto al suponer esto? Y se puede pensar en una mejor manera de administrar estos manipuladores, mientras que todavía me permite mantener esa funcionalidad encapsulada dentro de mi clase extendida?

Lo siento por la longitud del poste, y gracias de antemano por la ayuda!

-Funger

¿Fue útil?

Solución

Tiene razón en que AutoFilterValues ??ya habrán cambiado en ese momento, por lo que será desenganchando los manipuladores equivocadas, lo que resulta en una pérdida de memoria.

La solución es muy fácil. Hacer exactamente lo que está haciendo, pero utiliza un List<IList> en lugar de AutoFilterValues ??simplemente hacen referencia a:

private List<IList> _GridFilters;

y el uso ToList() para hacer una copia de los filtros de configurar los controladores en:

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

Desde _GridFilters es ahora un List<IList>, que también tendrá que cambiar los bucles:

foreach(IList autofilterValues in _GridFilters) 
  ...

La razón por la que esto funciona es que la lista actual de las listas de filtros viejos se copia en _GridFilters, en lugar de simplemente referencia a la propiedad AutoFilterValues.

Esta es una técnica general agradable que se puede aplicar en muchas situaciones.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top