我正在开发一个项目,该项目会ping一个地址列表并在屏幕上反映哪些地址不可ping。我当前的工作代码只是列在列表中,每次ping一个地址,并根据是否可以ping通来更改对象名称的颜色。
PingReply reply = ping.Send(pos[item.Index].IP, 100);
if (reply.Status == IPStatus.Success)
{
item.Forecolor = Color.Green;
}
else
{
item.ForeColor = Color.Red;
}
这与预期一样有效。问题是当ping处于活动状态时,UI会冻结。事实上,当ping发生时,我甚至无法移动窗口。当然,这只发生在失败的ping上。我限制了ping请求使用100
等待的时间,但这只会减少UI冻结的时间。所以,我研究了异步ping。现在,我只得到负面结果。以下是我试图使用的代码。
//pertinent part of code
Task<PingReply> result = Ping(pos[item.Index].IP);
if (result.Status == TaskStatus.Running || result.Status == TaskStatus.RanToCompletion)
{
item.ForeColor = Color.Green;
}
else
{
item.ForeColor = Color.Red;
}
//elsewhere in the code
public async Task<PingReply> Ping(string address)
{
var reply = await new Ping().SendPingAsync(address);
return reply;
}
就我试图做的事情而言,我不介意每个ping是否同步运行,只要它在与UI的单独线程上运行即可。我想确定如果我试图以某种方式操纵窗口(添加新位置,移动窗口本身等),错过的ping不会干扰用户体验。
我觉得这个问题正是我在条件下检查的问题,但由于我没有工作的代码/逻辑,条件可能只是表面的错误这里。
答案 0 :(得分:6)
很难理解为什么使用任务状态来确定ping是否成功。您可能应该像同步版本一样检查PingReply
。
PingReply reply = await Ping(pos[item.Index].IP);
if (reply.Status == IPStatus.Success)
...
答案 1 :(得分:0)
如果您在UI线程上同步执行ping操作,则无法从另一个线程更新UI。您有两种方法可以处理UI线程。第一种方法是使用BackgroundWorker
并在BackgroundWorker
的DoWork方法上同步执行ping操作,并将更新发送到UI线程以执行颜色更新。你可以强有力地让每个人都做很多,或者只是不断重复使用不同的参数。
另一种方法是保留您拥有的大部分代码,并同步ping,但使用anon方法包装在Task中,并使用带有更新UI的回调的Progress<T>
对象。此回调将在UI线程上注册,但可以从您的任务中调用。
以下是一个例子:
Progress prog = new Progress<Tuple<string,bool>>(p =>
{
String itemName = p.Item1;
bool success = p.Item2;
//locate item by name and set to color based on success
}
这应该在UI上的方法中创建,但可供类中的所有方法使用。
然后,您可以从异步Ping方法调用此进度对象,该方法将数据封送到您的UI线程并为您执行更新。