我目前正在使用一个可观察的集合来存储ListView的数据对象。将新对象添加到集合中工作正常,listView正确更新。但是,当我尝试更改集合中对象的某个属性时,listView将无法正确更新。例如,我有一个可观察的集合DataCollection。我试试
_DataCollections.ElementAt(count).Status = "Active";
由于按下按钮,我在长时间操作之前执行此更改。 listView不会反映更改。所以我添加了myListView.Items.Refresh()
;。这是有效的,但是在button_click方法完成之前,listView不会刷新,这在那时是不行的。
例如:
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(); });
}
然而,这似乎也不正常。任何提示或想法将不胜感激。
答案 0 :(得分:3)
为了解决这个问题,我创建了一个名为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);
}
答案 1 :(得分:3)
您必须使用正确的数据绑定技术,然后这将自动运行。
必需...
如果您执行这两项操作,则无需进行“刷新”调用或其他任何操作。设置触发INotifyPropertyChanged的属性将导致ItemTemplate的绑定更新。
在ObservableCollection中的类上实现INotifyPropertyChanged ... (如果你还不知道它,请查看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项之前......
更新第4项......
此处提供完整的代码示例: CODE SAMPLE
答案 2 :(得分:2)
你遇到了ObservableCollection的经典问题。它只会在添加或删除项目时通知。它不会在集合中项目的属性发生更改时通知。如果您希望收到此类更改的通知,则必须手动创建自己的自定义集合并在单个对象上添加/删除属性更改事件。对不起,老兄。