2010-11-29 11 views
8

Al utilizar el enlace de datos WPF, obviamente no puedo hacer algo a lo largo de las líneas MyCollection = new CollectionType<Whatever>(WhateverQuery()); ya que los enlaces tienen una referencia a la colección anterior. Mi solución hasta ahora ha sido MyCollection.Clear(); seguido de un foreach haciendo MyCollection.Add(item);, lo cual es bastante malo tanto para el rendimiento como para la estética.WPF: Reemplazar los contenidos de la colección databound sin Borrar/Agregar

ICollectionView, aunque bastante limpio, no resuelve el problema ya que es SourceCollection la propiedad es de solo lectura; Demonio, ya que habría sido una solución agradable y fácil.

¿Cómo están manejando este problema otras personas? Cabe mencionar que estoy haciendo MVVM y, por lo tanto, no puedo hurgar en las vinculaciones de controles individuales. Supongo que podría hacer un contenedor alrededor del ObservableCollection con un método ReplaceSourceCollection(), pero antes de seguir esa ruta me gustaría saber si hay alguna otra práctica recomendada.

EDIT:

Para Windows Forms, me gustaría enlazar controles contra un BindingSource, lo que me permite simplemente actualizar su DataSource propiedad y llamar al método ResetBindings() - presto, que subyace en la colección cambió de manera eficiente. Me esperaba que WPF databinding para soportar un escenario similar de la caja?

Código de ejemplo (pseudo-ish): el control WPF (ListBox, DataGrid, lo que sea que desee) está vinculado a la propiedad Users. Soy consciente de que las colecciones deben ser de sólo lectura para evitar los problemas demostrados por ReloadUsersBad(), pero luego el código malo para este ejemplo, obviamente, no se compilará :)

public class UserEditorViewModel 
{ 
    public ObservableCollection<UserViewModel> Users { get; set; } 

    public IEnumerable<UserViewModel> LoadUsersFromWhateverSource() { /* ... */ } 

    public void ReloadUsersBad() 
    { 
     // bad: the collection is updated, but the WPF control is bound to the old reference. 
     Users = new ObservableCollection<User>(LoadUsersFromWhateverSource()); 
    } 

    public void ReloadUsersWorksButIsInefficient() 
    { 
     // works: collection object is kept, and items are replaced; inefficient, though. 
     Users.Clear(); 
     foreach(var user in LoadUsersFromWhateverSource()) 
      Users.Add(user); 
    } 

    // ...whatever other stuff. 
} 
+0

¿Puede por favor publicar un código? – TalentTuner

+0

+1 buena pregunta. No he hecho nada en WPF por un tiempo, pero otra estructura en un idioma diferente tiene conceptos similares y resuelve este problema deteniendo el ciclo de ejecución, cambiando una gran cantidad de propiedades y luego deshaciendo el ciclo de ejecución. Estoy buscando algo similar. –

Respuesta

4

Si el objeto MyCollection es de implementos INotifyPropertyChanged, puede simplemente reemplazar la colección.

Un ejemplo:

public class MyClass : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    private ObservableCollection<Whatever> _myCollection; 

    private void NotifyChanged(string property) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(property)); 
    } 

    public ObservableCollection<Whatever> MyCollection 
    { 
     get 
     { 
      return _myCollection; 
     } 
     set 
     { 
      if (!ReferenceEquals(_myCollection, value)) 
      { 
       _myCollection = value; 
       NotifyChanged("MyCollection"); 
      } 
     } 
    } 
} 

Con esto, cuando se asigna una colección, WPF detecta esto y todo se actualiza.

Así es como resolvería esto.

+0

Por supuesto ... estoy bastante seguro de que incluso tuve que hacer eso antes. –

+0

D'oh!Tenía que ser algo simple y obvio, ¿no? : P – snemarch

+0

No hay problema, me alegro de poder ayudar. –

1

El siguiente enlace explica cómo implementar un método AddRange.

http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx

Parece que está pegado con la implementación de una sub-clase que maneja este caso correctamente.

Aparentemente, algunos controles no admiten notificaciones de cambio de recopilación por lotes. Al menos no lo hicieron cuando se escribió ese artículo. Aunque ahora deberías tener un poco más de información si quieres investigar más.

+0

Artículo decente para tratar con actualizaciones por lotes (en lugar de reemplazar por completo) - desagradable que 'ListCollectionView' solo admite actualizaciones de un solo elemento: | – snemarch

Cuestiones relacionadas