从BackgroundWorker/ProgressChanged事件中更新ObservableCollection
本文关键字:更新 ObservableCollection 事件 ProgressChanged BackgroundWorker | 更新日期: 2023-09-27 17:53:38
我正在编写一个简单的计算机故障排除工具。基本上,它只是一个WPF窗口,ListBox
绑定到ObservableCollection<ComputerEntry>
,其中ComputerEntry
是一个简单的类,包含计算机主机名和状态。该工具所做的只是ping列表中的每个计算名称,如果收到响应,则更新ComputerEntry.Status
以指示计算机已连接到某个网络…
BackgroundWorker
中运行实际的ping,并使用ReportProgress
方法来更新UI。
不幸的是,在对象更新后,ObservableCollection
似乎没有引发PropertyChanged
事件。集合使用新信息进行更新,但是ListBox
中的状态永远不会改变。大概是因为它不知道集合发生了变化。
[编辑]根据fantasticfix,这里的关键是:"ObservableCollection仅在列表被更改(添加、交换、删除)时触发。"由于我是在设置对象的属性而不是修改它,ObservableCollection没有通知列表更改——它不知道如何通知。在实现INotifyPropertyChanged
之后,一切都很好。相反,用一个新的更新实例替换列表中的对象也会解决这个问题。(/编辑)
顺便说一句,我正在使用c# 3.5,我不能在一个位置,我可以添加额外的依赖,如TPL。
作为一个简化的例子[没有更多的工作就不会编译…]:
//Real one does more but hey its an example...
public class ComputerEntry
{
public string ComputerName { get; private set; }
public string Status { get; set; }
public ComputerEntr(string ComputerName)
{
this.ComptuerName = ComputerName;
}
}
//...*In Window Code*...
private ObservableCollection<ComputerEntry> ComputerList { get; set; }
private BackgroundWorker RefreshWorker;
private void Init()
{
RefreshWorker = new BackgroundWorker();
RefreshWorker.WorkerReportsProgress = true;
RefreshWorker.DoWork += new DoWorkEventHandler(RefreshWorker_DoWork);
RefreshWorker.ProgressChanged += new ProgressChangedEventHandler(RefreshWorker_ProgressChanged);
}
private void Refresh()
{
RefreshWorker.RunWorkerAsync(this.ComputerList);
}
private void RefreshWorker_DoWork(object sender, DoWorkEventArgs e)
{
List<ComputerEntry> compList = e as List<ComputerEntry>;
foreach(ComputerEntry o in compList)
{
ComputerEntry updatedValue = new ComputerEntry();
updatedValue.Status = IndicatorHelpers.PingTarget(o.ComputerName);
(sender as BackgroundWorker).ReportProgress(0, value);
}
}
private void RefreshWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ComputerEntry updatedValue = new ComputerEntry();
if(e.UserState != null)
{
updatedValue = (ComputerEntry)e.UserState;
foreach(ComputerEntry o in this.ComputerList)
{
if (o.ComputerName == updatedValue.ComputerName)
{
o.Status = updatedValue.Status;
}
}
}
}
很抱歉混乱,但它的所有支持代码相当长。无论如何,void Refresh()
是从DispatcherTimer(未显示)调用的,该DispatcherTimer启动RefreshWorker.RunWorkerAsync(this.ComputerList);
。
我已经为此战斗了几天,所以我现在已经到了我实际上不再试图修改ObservableCollection
中直接引用的对象的地步。因此,在ComputerList集合中循环并直接设置属性是很难看的。
你知道这里发生了什么,我该如何解决它吗?
当你改变集合内项目的属性时,observableCollection不会触发(它怎么知道呢)。ObservableCollection仅在列表被更改(添加、交换、删除)时触发。
如果你想检测ComputerEntry属性的变化,该类必须实现INotifyPropertyChange接口(如果你知道MVVM,它就像一个轻量级的MVVM模式)
public class ComputerEntry : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void RaisePropertyChanged(String propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private String _ComputerName;
public String ComputerName
{
get
{
return _ComputerName;
}
set
{
if (_ComputerName != value)
{
_ComputerName = value;
this.RaisePropertyChanged("ComputerName");
}
}
}
}
在很长一段时间没有使用这个,但你不需要像INotifyPropertyChanged实现的东西吗?