【问题标题】:Implementing listener (subscription) in GUI using async extensions使用异步扩展在 GUI 中实现监听器(订阅)
【发布时间】:2012-01-02 19:09:20
【问题描述】:

这是我尝试使用的具有异步响应的 3 层应用程序的模型:

  • 图形界面
  • 后端
  • 远程服务器

图形界面:

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 将 对添加到一些线程安全字典中。 另一个工作线程从网络流中读取消息(消息头)并根据消息头中的字符串cmd调用动作。

现在的问题:

  • 当我需要订阅 GUI 元素以进行定期更新(不是单个回调)时,是否可以达到同样的简洁程度?

【问题讨论】:

    标签: c# asynchronous subscription async-await


    【解决方案1】:

    好吧,你可以把你拥有的东西放入一个循环中,例如:

    private async void StartReading()
    {
      while (true)
      {
        FloatValueLabel.Content = (await srvProtocol.ReadFloat("ReadFloatX")).ToString();
        await Task.Delay(1000);
      }
    }
    

    虽然我个人不喜欢“无限异步”循环。停止循环的唯一方法是抛出异常(错误或取消)。

    Rx library 更适合订阅。它允许高水平的 “简洁”,但学习曲线更陡峭。

    您还可以将所有订阅逻辑包装到模型/视图模型中。这在处理“更新”相同的概念值时特别有意义。在这种情况下,StartReading 将是您的模型/视图模型上的一个方法。它将使用async(用于无限异步循环)或ObserveOn(用于Rx)将更新带到UI线程,然后使用标准INotifyPropertyChanged/ObservableCollection间接更新UI。

    【讨论】:

    • 谢谢。这种循环是一种可能的解决方案,但你是对的:我确实只将它作为临时解决方法。我将研究 Rx,但我开始怀疑 TPL DataFlow 是否可以提供与我的示例中的风格一致的解决方案。
    • Stephen,在深入研究 Rx 之后,我同意您的回答确实是完整的,并且为我的问题提供了最连贯的答案。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    相关资源
    最近更新 更多