.net – WPF的F#异步事件处理程序类似于C#的异步和等待

如何在F#中编写异步 WPF(或 Windows窗体)事件处理程序?具体来说,是否有任何编码模式接近C#5的异步并等待?

这是一个完整的C#WPF应用程序:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

class Program
{
    static int IncrementSlowly(int prevIoUs)
    {
        Thread.Sleep(3000);
        if (prevIoUs == 2) throw new Exception("Oops!");
        return prevIoUs + 1;
    }

    static async void btn_Click(object sender,RoutedEventArgs e)
    {
        var btn = sender as Button;
        btn.IsEnabled = false;
        try
        {
            var prev = (int)btn.Content;
            btn.Content = await Task.Run(() => IncrementSlowly(prev));
        }
        catch (Exception ex)
        {
            btn.Content = ex.Message;
        }
        finally
        {
            btn.IsEnabled = true;
        }
    }

    [STAThread]
    static void Main(string[] args)
    {
        var btn = new Button() { Content = 0 };
        var win = new Window() { Content = btn };
        btn.Click += btn_Click;
        new Application().Run(win);
    }
}

我无法弄清楚使用F#的等价物.我使用异步工作流和异步方法的组合进行了多次尝试.它真的很快就真的很乱.我希望有一个简单的方法,我只是俯瞰.

这是我的起点,它将UI锁定在btn.Content< - incrementSlowly prev.接下来我该怎么办?

open System
open System.Threading
open System.Threading.Tasks
open System.Windows
open System.Windows.Controls

let incrementSlowly prevIoUs = 
    Thread.Sleep(3000)
    if prevIoUs = 2 then failwith "Oops!"
    prevIoUs + 1

let btn_Click (sender : obj) e = 
    let btn = sender :?> Button
    btn.IsEnabled <- false
    try 
        try 
            let prev = btn.Content :?> int
            btn.Content <- incrementSlowly prev
        with ex -> btn.Content <- ex.Message
    finally
        btn.IsEnabled <- true

[<EntryPoint>][<STAThread>]
let main _ = 
    let btn = new Button(Content = 0)
    let win = new Window(Content = btn)
    btn.Click.AddHandler(RoutedEventHandler(btn_Click))
    Application().Run(win)

顺便说一下,假设incrementSlowly不能被修改.

解决方法

第一步是使incrementSlowly异步.这在C#代码中实际上是同步的,这可能不是一个好主意 – 在实际场景中,这可能是与网络通信,因此通常这实际上可以是异步的:
let incrementSlowly prevIoUs = async {
  do! Async.Sleep(3000)
  if prevIoUs = 2 then failwith "Oops!"
  return prevIoUs + 1 }

现在,您可以使按钮单击处理程序也异步.我们稍后将使用Async.StartImmediate启动它以确保我们可以访问UI元素,因此我们现在不必担心调度程序或UI线程:

let btn_Click (sender : obj) e = async {
  let btn = sender :?> Button
  btn.IsEnabled <- false
  try 
    try 
      let prev = btn.Content :?> int
      let! next = incrementSlowly prev
      btn.Content <- next
    with ex -> btn.Content <- ex.Message
  finally
    btn.IsEnabled <- true }

最后一步是更改事件注册.像这样的东西应该做的伎俩:

btn.Click.Add(RoutedEventHandler(fun sender e ->
  btn_Click sender e |> Async.StartImmediate)

关键是Async.StartImmediate启动异步工作流程.当我们在UI线程上调用它时,它确保所有实际工作都在UI线程上完成(除非您明确地将其卸载到后台),因此可以安全地访问代码中的UI元素.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


原文地址:http://msdn.microsoft.com/en-us/magazine/cc163791.aspx 原文发布日期: 9/19/2005 原文已经被 Microsoft 删除了,收集过程中发现很多文章图都不全,那是因为原文的图都不全,所以特收集完整全文。 目录 前言 CLR启动程序
前言 随着近些年微服务的流行,有越来越多的开发者和团队所采纳和使用,它的确提供了很多的优势也解决了很多的问题,但是我们也知道也并不是银弹,提供优势的同时它也给我们的开发人员和团队也带来了很多的挑战。 为了迎接或者采用这些新技术,开发团队需要更加注重一些流程或工具的使用,这样才能更好的适应这些新技术所
最近因为比较忙,好久没有写博客了,这篇主要给大家分享一下PLINQ中的分区。上一篇介绍了并行编程,这边详细介绍一下并行编程中的分区和自定义分区。 先做个假设,假设我们有一个200Mb的文本文件需要读取,怎么样才能做到最优的速度呢?对,很显然就是拆分,把文本文件拆分成很多个小文件,充分利用我们计算机中
在多核CPU在今天和不久的将来,计算机将拥有更多的内核,Microsoft为了利用这个硬件特性,于是在Visual Studio 2010 和 .NET Framework 4的发布及以上版本中,添加了并行编程这个新特性,我想它以后势必会改变我们的开发方式。 在以前或者说现在,我们在并行开发的时候可
c语言输入成绩怎么判断等级
字符型数据在内存中的存储形式是什么
c语言怎么求字符串的长度并输出
c语言函数的三种调用方式是什么
c语言中保留两位小数怎么表示
double的输入格式符是什么
长整型输出格式是什么
C语言中文件包含的命令关键字是什么
c程序如何编写x的y次方
c语言开根号代码是什么
c语言怎么进行字符串比较
c语言怎么进行强制类型转换
c语言运算符的优先级顺序是什么
c++用什么软件编程
中序遍历是怎么遍历的
h文件和c文件的关系是什么