[英]Update ObservableCollection from BackgroundWorker/ProgressChanged Event
我正在编写一个简单的计算机故障排除工具。 基本上它只是一个 WPF Window 与一个ListBox
绑定到ObservableCollection<ComputerEntry>
其中ComputerEntry
是一个简单的 class 包含主机名和状态。 该工具所做的只是 ping 列表中的每个计算名称,如果收到响应,则更新ComputerEntry.Status
以指示计算机已连接到某处的网络...
然而,ping 可能需要一些时间,每台计算机最多需要几秒钟,具体取决于它是否必须超时。 所以我在BackgroundWorker
中运行实际 ping 并使用ReportProgress
方法更新 UI。
不幸的是,对象更新后ObservableCollection
似乎没有引发PropertyChanged
事件。 该集合确实会使用新信息进行更新,但ListBox
中的状态永远不会改变。 大概是因为它不知道集合发生了变化。
[编辑]根据 Fantasyfix,这里的关键是:“仅当列表更改(添加、交换、删除)时,ObservableCollection 才会触发。” 由于我是在设置 object 的属性而不是对其进行修改,因此 ObservableCollection 没有通知更改列表——它不知道如何进行。 实施INotifyPropertyChanged
后一切正常。 相反,用新的更新实例替换列表中的 object 也可以解决问题。 [/编辑]
顺便说一句,我正在使用 C# 3.5 而我不在 position 中,我可以在其中添加额外的依赖项,例如 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;
}
}
}
}
很抱歉混乱,但所有支持代码都相当长。 无论如何,从 DispatcherTimer(未显示)调用void Refresh()
,它启动RefreshWorker.RunWorkerAsync(this.ComputerList);
.
我已经为此奋斗了几天,所以我现在已经到了我实际上不再尝试直接修改ObservableCollection
中引用的对象的地步。 因此,丑陋的循环通过 ComputerList 集合并直接设置属性。
知道这里发生了什么以及如何解决它吗?
当您更改集合内项目的属性时,observableCollection 不会触发(它甚至应该如何知道)。 ObservableCollection 仅在列表更改(添加、交换、删除)时触发。
如果你想检测 ComputerEntry 属性的变化,class 必须实现 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 这样的实现吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.