c# - 启动时的 C# WPF 异步
问题描述
我尝试构建一个简单的 WPF 应用程序并listbox
在MainWindow
. 背景是它 ping 一些机器,但我希望 GUI 已经打开,并且每当 ping 完成时,listbox
应该更新内容。
让我展示我的代码。主窗口.xaml.cs
public ObservableCollection<String> LbStatus
{
get { return BL.GetStatus(); }
}
BL.cs
public static ObservableCollection<string> GetStatus()
{
List<string> hostnames = new List<String>(GetHostnames());
ObservableCollection<string> status = new ObservableCollection<string>();
foreach(string hostname in hostnames)
{
Task<string> task = Task.Run(async () => await
PingHost(HM.GetHostname(hostname)));
status.Add(task.Result);
}
return status;
}
static public async Task<string> PingHost(string hostname)
{
Ping x = new Ping();
try
{
PingReply reply = await x.SendPingAsync(hostname, 5000);
if (reply.Status == IPStatus.Success)
{
return "Online";
}
else
return "Offline";
}
catch (Exception excep)
{
//exception handling
}
}
我认为问题在于我的程序等待task.result
. 但在我的脑海中,它应该只是跳过并且什么都不返回,并且每当它完成时它应该返回正确的字符串。但是(这就是我这样做的全部原因)GUI 应该已经启动了。
我希望我的问题是有道理的,有人可以帮助我:-)
谢谢!
解决方案
我建议您进行一些更改。首先,您对该属性
的实现非常可疑。
在这样的实现中,每次访问此属性时,都会创建一个新集合,这可能会导致:它们的不同状态;同时调用多次该方法。还有许多其他问题与多个集合实例的存在相关,但是当视图“认为”这是同一个实例时。
通过为您提供此属性的此实现:LbStatus
BL.GetStatus()
private ObservableCollection<string> _lbStatus;
public ObservableCollection<string> LbStatus
{
get
{
if (_lbStatus == null)
_lbStatus = BL.GetStatus();
return _lbStatus;
}
}
第二个问题,在方法中BL.GetStatus()
- 您需要返回集合而不等待其完成。
因此,填充它的循环应该在一个单独的异步方法中。
该BL.GetStatus()
方法应该调用这个异步方法,而不是等待它完成。
我建议你这个实现:
public static ObservableCollection<string> GetStatus()
{
ObservableCollection<string> status = new ObservableCollection<string>();
FillStatus(status);
return status;
}
public static async Task FillStatus(ICollection<string> status)
{
foreach (string hostname in GetHostnames())
{
status.Add(await PingHost(HM.GetHostname(hostname)));
}
}
实现属性的另一种选择,考虑到将方法分为两部分。
它只会使用异步部分。
private ObservableCollection<string> _lbStatus;
public ObservableCollection<string> LbStatus
{
get
{
if (_lbStatus == null)
{
_lbStatus = new ObservableCollection<string>();
BL.FillStatus(_lbStatus);
}
return _lbStatus;
}
}
考虑到集合在 UI 元素中的使用,它的更改应该发生在主 UI 线程中。为此,您必须将 Dispatcher 传递给该方法。
public static async Task FillStatus(ICollection<string> status, Dispatcher dispatcher)
{
foreach (string hostname in GetHostnames())
{
string item = await PingHost(HM.GetHostname(hostname));
dispatcher.BeginInvoke(new Action(() => status.Add(item)))
}
}
private ObservableCollection<string> _lbStatus;
public ObservableCollection<string> LbStatus
{
get
{
if (_lbStatus == null)
{
_lbStatus = new ObservableCollection<string>();
BL.FillStatus(_lbStatus, Dispatcher);
}
return _lbStatus;
}
}
推荐阅读
- android - Firebase 电子邮件未验证覆盖
- python - 绘制从 CSV 文件派生的数据框(带有特定时间)
- c++ - 如何将输入存储为字符串,直到在 C++ 中输入了一个或多个特定字符串?
- c++ - 在执行虚纯函数时调用构造函数抛出“分配抽象类类型的对象”错误
- javascript - 试图从抛出未定义的函数中获取数据
- google-cloud-platform - BigQuery 中 Hive 的显示分区的替代方案
- c# - Websockets:从NodeJS websocket服务器到带有WebSocketSharp的C#客户端的多个响应
- javascript - 我想通过使用来自 Firestore 的地图来显示我的标签“等素食主义者、意大利面……等等”?
- acumatica - Acumatica - 数据视图 LSAMProdItem_lotseropts
- firebase - 从 Firebase 读取 UserData 的问题