繁体   English   中英

使用F#和异步工作流在Silverlight中拖放

[英]Drag and Drop in Silverlight with F# and Asynchronous Workflows

我正在尝试使用F#和异步工作流在Silverlight中实现拖放。

我只是试图在画布上拖动一个矩形,使用两个循环来处理两个状态(等待和拖动),这是我从Tomas Petricek的书“Real-world Functional Programming”中得到的一个想法,但我遇到了一个问题:

与WPF或WinForms不同,Silverlight的MouseEventArgs不包含有关按钮状态的信息,因此我无法通过检查是否不再按下鼠标左键来从拖动循环返回。 我只是通过引入一个可变标志来解决这个问题。

有没有人有这个解决方案,这不涉及可变状态?

这是相关的代码部分(请原谅拖拽拖动代码,将矩形捕捉到鼠标指针):

type MainPage() as this =
    inherit UserControl()
    do
        Application.LoadComponent(this, new System.Uri("/SilverlightApplication1;component/Page.xaml", System.UriKind.Relative))
    let layoutRoot : Canvas = downcast this.FindName("LayoutRoot")
    let rectangle1 : Rectangle = downcast this.FindName("Rectangle1")

    let mutable isDragged = false

    do
        rectangle1.MouseLeftButtonUp.Add(fun _ -> isDragged <- false)

        let rec drag() = async {
            let! args = layoutRoot.MouseMove |> Async.AwaitEvent
            if (isDragged) then
                Canvas.SetLeft(rectangle1, args.GetPosition(layoutRoot).X)
                Canvas.SetTop(rectangle1, args.GetPosition(layoutRoot).Y)
                return! drag()
            else
                return()
            } 
        let wait() = async {
            while true do
                let! args = Async.AwaitEvent rectangle1.MouseLeftButtonDown
                isDragged <- true
                do! drag()
            }

        Async.StartImmediate(wait())
        ()

非常感谢您的宝贵时间!

解决此问题的方法是使用重载的AwaitEvent ,它允许您等待两个事件。 而不是只是等待MouseMove ,你也可以等待MouseUp事件 - 在第一种情况下,你可以继续移动,在第二种情况下,你可以从循环返回并停止拖放(这实际上将在本书的后面讨论)第16.4.5节)。

这是代码 - 它实际上使用方法的AwaitObservable变体(见下文),这是一个更好的选择,因为它适用于Observable.map和类似的组合器(如果你想使用它们)。

let! args = Async.AwaitObservable(layoutRoot.MouseMove, layoutRoot.MouseUp)
match args with
| Choice1Of2(args) ->
    // Handle the 'MouseMove' event with 'args' here
    Canvas.SetLeft(rectangle1, args.GetPosition(layoutRoot).X)  
    Canvas.SetTop(rectangle1, args.GetPosition(layoutRoot).Y)  
    return! drag()  
| Choice2Of2(_) ->
    // Handle the 'MouseUp' event here
    return()  

据我所知,重载的AwaitObservable方法在F#库中尚未提供,但您可以从本书的网站上获取它,或者您可以使用以下代码:

// Adds 'AwaitObservable' that takes two observables and returns
// Choice<'a, 'b> containing either Choice1Of2 or Choice2Of2 depending
// on which of the observables occurred first
type Microsoft.FSharp.Control.Async with   
  static member AwaitObservable(ev1:IObservable<'a>, ev2:IObservable<'b>) = 
    Async.FromContinuations((fun (cont,econt,ccont) -> 
      let rec callback1 = (fun value ->
        remover1.Dispose()
        remover2.Dispose()
        cont(Choice1Of2(value)) )
      and callback2 = (fun value ->
        remover1.Dispose()
        remover2.Dispose()
        cont(Choice2Of2(value)) )
      // Attach handlers to both observables
      and remover1 : IDisposable  = ev1.Subscribe(callback1) 
      and remover2 : IDisposable  = ev2.Subscribe(callback2) 
      () ))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM