【发布时间】:2011-09-01 16:16:50
【问题描述】:
我正在 WPF 中实现 Tracert 的可视化版本(作为学习练习),结果转到列表框。问题是 (1) 绑定到 tracertDataView 的列表框没有更新,但 (2) 我的整个应用程序挂起。
我确定 #2 是线程问题,但我不确定如何纠正它(以正确的方式)。此外,我不确定我更新/绑定“DoTrace”结果的技术是否正确。
这是我在 App.xaml
中的数据源<Window.Resources>
<CollectionViewSource
Source="{Binding Source={x:Static Application.Current}, Path=TracertResultNodes}"
x:Key="tracertDataView" />
</Window.Resources>
App.xaml.cs
public partial class App : Application
{
private ObservableCollection<TracertNode> tracertResultNodes = new ObservableCollection<TracertNode>();
public void AppStartup(object sender, StartupEventArgs e)
{
// NOTE: Load sample data does work correctly.. and displays on the screen.
// subsequent updates do not display
LoadSampleData();
}
private void LoadSampleData()
{
TracertResultNodes = new ObservableCollection<TracertNode>();
TracertNode t = new TracertNode();
t.Address = new System.Net.IPAddress(0x2414188f);
t.RoundTripTime = 30;
t.Status = System.Net.NetworkInformation.IPStatus.BadRoute;
TracertResultNodes.Add(t);
}
public ObservableCollection<TracertNode> TracertResultNodes
{
get { return this.tracertResultNodes; }
set { this.tracertResultNodes = value; }
}
}
这是MainWindow代码
public partial class MainWindow : Window
{
CollectionViewSource tracertDataView;
TraceWrapper _tracertWrapper = null;
public MainWindow()
{
InitializeComponent();
_tracertWrapper = new TraceWrapper();
tracertDataView = (CollectionViewSource)(this.Resources["tracertDataView"]);
}
private void DoTrace_Click(object sender, RoutedEventArgs e)
{
((App)Application.Current).TracertResultNodes = _tracertWrapper.Results;
_tracertWrapper.DoTrace("8.8.8.8", 30, 50);
}
}
仅供参考实例对象“traceWrapper.DoTrace”的内部实现细节
/// <summary>
/// Trace a host. Note that this object internally calls the Async implementation of .NET's PING.
// It works perfectly fine in a CMD host, but not in WPF
/// </summary>
public ObservableCollection<TracertNode> DoTrace(string HostOrIP, int maxHops, int TimeOut)
{
tracert = new Tracert();
// The following is triggered for every host that is found, or upon timeout
// (up to 30 times by default)
AutoResetEvent wait = new AutoResetEvent(false);
tracert.waiter = wait;
tracert.HostNameOrAddress = HostOrIP;
tracert.Trace();
this.Results = tracert.NodeList;
while (tracert.IsDone == false)
{
wait.WaitOne();
IsDone = tracert.IsDone;
}
return tracert.NodeList;
}
【问题讨论】:
-
经验教训 #1:“您不能从另一个线程更新 ObservableCollections。”谢谢@Salvatore
标签: c# wpf multithreading observablecollection autoresetevent