我正在编写一个简单的计算机故障排除工具。基本上它只是一个ListBox
绑定到ObservableCollection<ComputerEntry>
的WPF窗口,其中ComputerEntry
是一个包含计算机主机名和状态的简单类。所有工具都会对列表中的每个计算名称执行ping操作,如果收到响应,则会更新ComputerEntry.Status
以指示计算机已在某处连接到网络...
然而,Ping可能需要一些时间,每台计算机最多可能需要几秒钟,具体取决于是否需要超时。所以我在BackgroundWorker
中运行实际的ping并使用ReportProgress
方法更新UI。
不幸的是,ObservableCollection
似乎在对象更新后没有引发PropertyChanged
事件。该集合会使用新信息进行更新,但状态永远不会在ListBox
中更改。大概是因为它不知道收藏品已经改变了。
[编辑]
Per 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(未显示)调用,启动RefreshWorker.RunWorkerAsync(this.ComputerList);
。
我已经打了好几天了,所以我现在已经到了我实际上不再试图直接修改ObservableCollection
中引用的对象了。因此,丑陋的循环遍历ComputerList集合并直接设置属性。
有什么想法在这里发生以及如何解决它?
答案 0 :(得分:1)
当您更改集合内部的项目的属性时,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");
}
}
}
}
答案 1 :(得分:0)
长时间没有使用过这个,但是你不需要实现像INotifyPropertyChanged这样的东西吗?