代码之家  ›  专栏  ›  技术社区  ›  Ronald Wildenberg

在F中同时等待多个事件中的任何事件#

  •  7
  • Ronald Wildenberg  · 技术社区  · 14 年前

    在F#中,我知道如何使用异步等待一个事件 Async.AwaitEvent :

    let test = async {
      let! move = Async.AwaitEvent(form.MouseMove)
      ...handle move... }
    

    假设我想等待 MouseMove 或者 KeyDown 事件。我想要这样的东西:

    let! moveOrKeyDown = Async.AwaitEvent(form.MouseMove, form.KeyDown)
    

    此函数不存在,但是否有其他方法来执行此操作?

    4 回复  |  直到 14 年前
        1
  •  12
  •   desco    14 年前
    let ignoreEvent e = Event.map ignore e
    
    let merged = Event.merge (ignoreEvent f.KeyDown) (ignoreEvent f.MouseMove)
    Async.AwaitEvent merged
    

    编辑: 另一个保留原始类型的版本

    let merged = Event.merge (f.KeyDown |> Event.map Choice1Of2) (f.MouseMove |> Event.map Choice2Of2)
    Async.AwaitEvent merged
    

    编辑2 托马斯·佩特里切克

    let e1 = f.KeyDown |> Observable.map Choice1Of2
    let e2 = f.MouseMove |> Observable.map Choice2Of2
    let! evt = Observable.merge e1 e2 |> Async.AwaitObservable
    

    可观察的 here (《Silverlight中的反应演示》作者:托马斯·佩特里切克)。

        2
  •  12
  •   gradbot    14 年前

    我使用了一个方法的实现,您在 talk about reactive programming

    我使用的版本 IObservable IEvent AwaitObservable ). 有一些 使用时 Event.merge Event 模块)以及 AwaitEvent ,所以你应该使用 Observable.merge 等等 相反。

    对这个问题进行了更详细的描述 here (请参阅第3节了解一个清晰的示例)。简而言之-当你使用 事件.合并 ,它将处理程序附加到源事件(例如。 MouseDown ),但它不会在您完成等待使用后删除处理程序 等待事件

    简单正确的解决方案(基于什么 德斯科

    let rec loop () = async {
      let e1 = f.KeyDown |> Observable.map Choice1Of2
      let e2 = f.MouseMove |> Observable.map Choice2Of2
      let! evt = Observable.merge e1 e2 |> Async.AwaitObservable
      // ...
      return! loop() } // Continue looping
    

    顺便说一句:你可能还想看看 this article (根据我书的第16章)。

        3
  •  4
  •   gradbot    14 年前

    为了理解发生了什么,我查阅了源代码事件.map, 事件.合并还有选择。

    type Choice<'T1,'T2> = 
        | Choice1Of2 of 'T1 
        | Choice2Of2 of 'T2
    
    [<CompiledName("Map")>]
    let map f (w: IEvent<'Delegate,'T>) =
        let ev = new Event<_>() 
        w.Add(fun x -> ev.Trigger(f x));
        ev.Publish
    
    [<CompiledName("Merge")>]
    let merge (w1: IEvent<'Del1,'T>) (w2: IEvent<'Del2,'T>) =
        let ev = new Event<_>() 
        w1.Add(fun x -> ev.Trigger(x));
        w2.Add(fun x -> ev.Trigger(x));
        ev.Publish
    

    这意味着我们的解决方案将创建3个新事件。

    async {
        let merged = Event.merge 
                         (f.KeyDown |> Event.map Choice1Of2) 
                         (f.MouseMove |> Event.map Choice2Of2)
        let! move = Async.AwaitEvent merged
    }
    

    type EventChoice<'T1, 'T2> = 
        | EventChoice1Of2 of 'T1
        | EventChoice2Of2 of 'T2
        with 
        static member CreateChoice (w1: IEvent<_,'T1>) (w2: IEvent<_,'T2>) =
            let ev = new Event<_>()
            w1.Add(fun x -> ev.Trigger(EventChoice1Of2 x))
            w2.Add(fun x -> ev.Trigger(EventChoice2Of2 x))
            ev.Publish
    

    这是我们的新代码。

    async {
        let merged = EventChoice.CreateChoice form.MouseMove form.KeyDown
        let! move = Async.AwaitEvent merged
    }
    
        4
  •  0
  •   kvb    14 年前

    Event.map Event.merge

    let eventOccurs e = e |> Event.map ignore
    let mouseOrKey = Event.merge (eventOccurs frm.MouseMove) (eventOccurs frm.KeyDown)
    

    那你可以用 Async.AwaitEvent MouseMove KeyDown 有相同的类型,你可以跳过 然后直接合并。

    编辑

    Observable 优先于 Event 一个。