簡體   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