Я не понимаю, как вы использовали AutoResetEvent, я думаю, он не должен использоваться таким образом:)
Но поскольку трассировка уже запущена в другом потоке, вы уверены, что нет события«OnTracertComplete» или что-то подобное в вашем классе Tracert?
Если нет, то почему вы просто не добавляете DispatchTimer в свое приложение?Этот таймер будет периодически опрашивать, пока tracert.IsDone становится истиной.Если вы блокируете выполнение потока приложения до завершения операции, вы блокируете выполнение цикла событий окна, чтобы окно никогда не обновлялось.
Еще одна важная вещь: вы не можете обновить ObservableCollections из другого потока.Будьте осторожны и убедитесь, что все, что обновляется в окне WPF, выполняется из того же потока окна.Не знаю, что именно делает ваш класс Trace, но вашей проблемой здесь, конечно, является цикл ожидания, который не имеет смысла в приложении с графическим интерфейсом.
Используйте события уведомлений или таймер для опросарезультат.Таймер с разрешением в 1 секунду кажется мне подходящим для этой конкретной реализации, и прирост производительности абсолютно минимален.
Это возможная реализация, если вы можете изменить класс Tracert.
public delegate void TracertCallbacHandler(Tracert sender, TracertNode newNode);
public class Tracert
{
public event TracertCallbacHandler NewNodeFound;
public event EventHandler TracertCompleted;
public void Trace()
{
....
}
// This function gets called in tracert thread\async method.
private void FunctionCalledInThreadWhenPingCompletes(TracertNode newNode)
{
var handler = this.NewNodeFound;
if (handler != null)
handler(this, newNode);
}
// This function gets called in tracert thread\async methods when everything ends.
private void FunctionCalledWhenEverythingDone()
{
var handler = this.TracertCompleted;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
А вот код для запуска tracert, это TracertWrapper.
// Keep the observable collection as a field.
private ObservableCollection<TracertNode> pTracertNodes;
// Keep the instance of the running tracert as a field, we need it.
private Tracert pTracert;
public bool IsTracertRunning
{
get { return this.pTracert != null; }
}
public ObservableCollection<TracertNode> DoTrace(string hostOrIP, int maxHops, int timeOut)
{
// If we are not already running a tracert...
if (this.pTracert == null)
{
// Clear or creates the list of tracert nodes.
if (this.pTracertNodes == null)
this.pTracertNodes = new ObservableCollection<TracertNode>();
else
this.pTracertNodes.Clear();
var tracert = new Tracert();
tracert.HostNameOrAddress = hostOrIP;
tracert.MaxHops = maxHops;
tracert.TimeOut = timeOut;
tracert.NewNodeFound += delegate(Tracert sender, TracertNode newNode)
{
// This method is called inside Tracert thread.
// We need to use synchronization context to execute this method in our main window thread.
SynchronizationContext.Current.Post(delegate(object state)
{
// This method is called inside window thread.
this.OnTracertNodeFound(this.pTracertNodes, newNode);
}, null);
};
tracert.TracertCompleted += delegate(object sender, EventArgs e)
{
// This method is called inside Tracert thread.
// We need to use synchronization context to execute this method in our main window thread.
SynchronizationContext.Current.Post(delegate(object state)
{
// This method is called inside window thread.
this.OnTracertCompleted();
}, null);
};
tracert.Trace();
this.pTracert = tracert;
}
return this.pTracertNodes;
}
protected virtual void OnTracertCompleted()
{
// Remove tracert object,
// we need this to let the garbage collector being able to release that objects.
// We need also to allow another traceroute since the previous one completed.
this.pTracert = null;
System.Windows.MessageBox.Show("TraceRoute completed!");
}
protected virtual void OnTracertNodeFound(ObservableCollection<TracertNode> collection, TracertNode newNode)
{
// Add our tracert node.
collection.Add(newNode);
}