使用异步扩展在GUI中实现侦听器(订阅)
本文关键字:侦听器 实现 订阅 GUI 异步 扩展 | 更新日期: 2023-09-27 18:19:10
这是我尝试使用的具有异步响应的3层应用程序的模型:
- GUI 后端远程服务器
private async void readFloatButton_Click(object sender, RoutedEventArgs e)
{
FloatValueLabel.Content = (await srvProtocol.ReadFloat("ReadFloatX")).ToString();
}
后台(使用内部变量binReader和connection)
public Task<float> ReadFloat(string cmd)
{
var tcs1 = new TaskCompletionSource<float>();
var floatTask = tcs1.Task;
RegisterResponse(cmd,
() =>
tcs1.SetResult(_binReader.ReadSingle());
);
// We are ready: now send request to server(assuming that this is a quick operation)
connection.Send(cmd);
return floatTask;
}
此处RegisterResponse添加了<键,动作> pair到某个线程安全的字典。另一个工作线程从网络流消息(消息头)中读取消息,并根据消息头中的字符串cmd调用操作。
现在的问题是:
- 当我需要订阅GUI元素以进行定期更新(而不是单个回调)时,是否有可能达到相同的简洁性级别?
嗯,你可以把你有的放到一个循环中,例如:
private async void StartReading()
{
while (true)
{
FloatValueLabel.Content = (await srvProtocol.ReadFloat("ReadFloatX")).ToString();
await Task.Delay(1000);
}
}
虽然我个人不喜欢"无限异步"循环。停止循环的唯一方法是抛出异常(错误或取消)。
Rx库更适合于订阅。它允许高水平的"简洁",但学习曲线更陡峭。
您还可以将所有订阅逻辑包装到一个Model/ViewModel中。这在处理"更新"相同的概念值时尤其有意义。在这种情况下,StartReading
将是您的模型/ViewModel上的方法。它将使用async
(用于无限异步循环)或ObserveOn
(用于Rx)将更新带到UI线程,然后使用标准INotifyPropertyChanged
/ObservableCollection
间接更新UI。