ListView не обновляется правильно с ObservableCollection - PullRequest
8 голосов
/ 01 июля 2011

В настоящее время я использую наблюдаемую коллекцию для хранения своих объектов данных для ListView. Добавление новых объектов в коллекцию работает просто отлично, а listView обновляется правильно. Однако, когда я пытаюсь изменить одно из свойств объекта в коллекции, listView не будет обновляться должным образом. Например, у меня есть наблюдаемая коллекция DataCollection. Я стараюсь

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

Я выполняю это изменение перед длительной операцией из-за нажатия кнопки. ListView не будет отражать изменение. Поэтому я добавляю myListView.Items.Refresh() ;. Это работает, однако listView не обновляется до тех пор, пока не будет завершен метод button_click, что к тому времени не принесло пользы. Например:

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

Состояние никогда не переходит в «Активный», оно сразу переходит в «Завершено» после завершения метода. Я также попытался использовать диспетчер, как это:

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

    }

Однако, похоже, это тоже не работает правильно. Любые советы или идеи будут оценены.

Ответы [ 3 ]

3 голосов
/ 01 июля 2011

Для решения этой проблемы я создал класс VeryObservableCollection. Для каждого добавляемого объекта он подключает событие NotifyPropertyChanged объекта к обработчику, который вызывает событие CollectionChanged. Для каждого удаленного объекта он удаляет обработчик. Очень просто и даст вам именно то, что вы хотите. Неполный код:

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);
}
3 голосов
/ 26 октября 2015

Вы должны использовать правильные методы привязки данных, и тогда это будет работать автоматически.

Обязательно ...

  1. Реализуйте INotifyPropertyChanged для вашего класса внутри ObservableCollection (и убедитесь, чтовы запускаете событие, когда устанавливаете свойства для этого класса)
  2. На ItemTemplate вашего ListView убедитесь, что вы используете привязку к свойствам

Если вы делаете эти двавещи, нет необходимости в вызове «Обновить» или что-то еще.Установка свойства, запускающего INotifyPropertyChanged, приведет к обновлению привязки ItemTemplate.

Реализация INotifyPropertyChanged для вашего класса в ObservableCollection ... (посмотрите на класс BindableBase, если вы этого не сделаетеуже знаете об этом)

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

Ваш ListView

<ListView
    x:Name="listView">

    <ListView.ItemTemplate>
        <DataTemplate>

            <StackPanel>

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

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

            </StackPanel>

        </DataTemplate>
    </ListView.ItemTemplate>

</ListView>

Ваша коллекция ObservableCollection ...

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

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

Добавление вещей в коллекцию работает ...

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

И обновление, что вы просили, работает ...

ToDoItem item = _toDoItems[randomIndex];

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

Нет вызовов "Обновить" или что-либо еще, что нужно.Сам элемент обновляется без изменения списка.

Перед обновлением Элемент 4 ...

Before updating Item 4

После обновления Item 4 ...

After updating Item 4

Полный образец кода доступен здесь: CODEОБРАЗЕЦ

2 голосов
/ 01 июля 2011

Вы столкнулись с классической проблемой с ObservableCollection. он только уведомляет, когда элемент добавлен или удален. он НЕ уведомляет, когда изменяется свойство элемента в коллекции. если вы хотите получать уведомления о таких изменениях, вам нужно будет создать собственную коллекцию и добавить / удалить события измененных свойств для отдельных объектов вручную. извини, чувак.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...