2011-06-30 13 views
8

Actualmente estoy usando una colección observable para almacenar mis objetos de datos para un ListView. Agregar nuevos objetos a la colección funciona bien, y la lista se actualiza correctamente. Sin embargo, cuando intento cambiar una de las propiedades de un objeto en la colección, listView no se actualizará correctamente. Por ejemplo, tengo una colección observable DataCollection. IntentoListView no se actualizó correctamente con ObservableCollection

_DataCollections.ElementAt(count).Status = "Active"; 

Realizo este cambio antes de una operación prolongada debido a la presión de un botón. ListView no reflejará el cambio. Entonces agrego myListView.Items.Refresh();. Esto funciona, sin embargo, el ListView no se actualiza hasta que el método button_click esté completo, lo cual no es bueno para entonces. Por ejemplo:

button1_Click(...) 
    { 
     _DataCollections.ElementAt(count).Status = "Active"; 
     myListView.Items.Refresh(); 
     ExecuteLongOperation(); 
     _DataCollections.ElementAt(count).Status = "Finished"; 
     myListView.Items.Refresh(); 
    } 

El estado nunca Ir a "Activo", que irá directamente a "Terminado" después de que el método se completa. También he intentado usar un despachador de la siguiente manera:

button1_Click(...) 
    { 
     this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, 
      (NoArgDelegate)delegate { _DataCollection.ElementAt(count).Status = "Active"; myListView.Items.Refresh(); }); 

     ExecuteLongOperation(); 
    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, 
      (NoArgDelegate)delegate { _DataCollection.ElementAt(count).Status = "Finished"; myListView.Items.Refresh(); }); 

    } 

Sin embargo, eso no parece funcionar correctamente tampoco. Cualquier consejo o idea sería apreciado.

Respuesta

3

Para resolver esto, creé una clase llamada VeryObservableCollection. Para cada objeto que agrega, engancha el evento NotifyPropertyChanged del objeto a un controlador que desencadena un evento CollectionChanged. Para cada objeto eliminado, elimina el controlador. Muy simple y le dará exactamente lo que quiere. Código parcial:

public class VeryObservableCollection<T> : ObservableCollection<T> 

/// <summary> 
/// Override for setting item 
/// </summary> 
/// <param name="index">Index</param> 
/// <param name="item">Item</param> 
protected override void SetItem(int index, T item) 
{ 
    try 
    { 
     INotifyPropertyChanged propOld = Items[index] as INotifyPropertyChanged; 
     if (propOld != null) 
      propOld.PropertyChanged -= new PropertyChangedEventHandler(Affecting_PropertyChanged); 
    } 
    catch (Exception ex) 
    { 
     Exception ex2 = ex.InnerException; 
    } 
    INotifyPropertyChanged propNew = item as INotifyPropertyChanged; 
    if (propNew != null) 
     propNew.PropertyChanged += new PropertyChangedEventHandler(Affecting_PropertyChanged); 

    base.SetItem(index, item); 
} 
+0

necesito mucho tiempo para encontrar la implementación correcta del método Affecting_PropertyChanged ... solo necesita una línea: 'MyBase.OnCollectionChanged (New NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Reset))' y recomiendo sobrescribir InsertItem y RemoveItem de ObservableCollection, porque SetItem no lo hizo no funciona para mí –

+0

@Felix, sí, había más. La implementación de la clase tiene más de 800 líneas. Dije que había publicado un código parcial, principalmente para dar una idea general. –

+0

Escribí esto para otras personas que encuentran esta publicación y no saben cómo implementar estas líneas de código. No fue una corrección, solo una extensión para que esto funcione. :) pero ¿por qué tu clase tiene una longitud de 800 líneas? Realmente me gustaría ver la implementación completa de tu clase. –

2

Se ha encontrado con el problema clásico con ObservableCollection. solo notifica cuando se agrega o elimina un elemento. NO notifica cuando cambia una propiedad de un artículo en la colección. si desea que se le notifiquen dichos cambios, tendrá que crear su propia colección personalizada y agregar/eliminar los eventos modificados por la propiedad en los objetos individuales manualmente. Lo siento amigo.

3

Debe utilizar las técnicas adecuadas de enlace de datos, y esto funcionará automáticamente.

Obligatorio ...

  1. Implementar INotifyPropertyChanged en su clase dentro de la ObservableCollection (y asegurarse de que está activa el evento cuando se está configurando las propiedades de esa clase)
  2. En ItemTemplate de su ListView, será Asegúrese de estar usando Encuadernación a las propiedades

Si hace estas dos cosas, no hay necesidad de una llamada "Actualizar" o cualquier otra cosa. Establecer una propiedad que desencadena INotifyPropertyChanged hará que la vinculación de ItemTemplate se actualice.

Ejecución INotifyPropertyChanged en su clase dentro de la ObservableCollection ... (consultar la clase BindableBase si usted no sabe acerca de lo que ya)

public class ToDoItem : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     set { SetProperty(ref _name, value); } 
    } 

    private DateTime _date; 
    public DateTime Date 
    { 
     get { return _date; } 
     set { SetProperty(ref _date, value); } 
    } 

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName]string propertyName = null) 
    { 
     if (object.Equals(storage, value)) return false; 

     storage = value; 
     this.OnPropertyChanged(propertyName); 
     return true; 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
     var eventHandler = this.PropertyChanged; 
     if (eventHandler != null) 
     { 
      eventHandler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

Su ListView

<ListView 
    x:Name="listView"> 

    <ListView.ItemTemplate> 
     <DataTemplate> 

      <StackPanel> 

       <TextBlock 
        Text="{Binding Name}"/> 

       <TextBlock 
        Text="{Binding Date}"/> 

      </StackPanel> 

     </DataTemplate> 
    </ListView.ItemTemplate> 

</ListView> 

Su ObservableCollection ...

private ObservableCollection<ToDoItem> _toDoItems = new ObservableCollection<ToDoItem>(); 

// Assign the collection to the ListView 
listView.ItemsSource = _toDoItems; 

añadir cosas a las obras de la colección ...

_toDoItems.Add(new ToDoItem() 
{ 
    Name = "Item " + (_toDoItems.Count + 1), 
    Date = DateTime.Now 
}); 

y actualización, lo que pedían por obras ...

ToDoItem item = _toDoItems[randomIndex]; 

item.Name = "Updated " + item.Name; 
item.Date = DateTime.Now; 

No hay llamadas para "Actualizar" o cualquier otra cosa necesaria. El elemento en sí se actualiza, sin que la lista cambie.

Antes de actualizar Tema 4 ...

Before updating Item 4

Después de actualizar Tema 4 ...

After updating Item 4

muestra completa de código disponible aquí:CODE SAMPLE

Cuestiones relacionadas