使用F#和异步工作流在Silverlight中拖放 [英] Drag and Drop in Silverlight with F# and Asynchronous Workflows
问题描述
我正在使用F#和异步工作流程来实现Silverlight中的拖放。
I'm trying to implement drag and drop in Silverlight using F# and asynchronous workflows.
我只是试图在画布上拖动一个矩形,使用两个州的两个循环(等待和拖动),我从Tomas Petricek的书真实世界功能编程中得到的想法,但是我遇到了一个问题:
I'm simply trying to drag around a rectangle on the canvas, using two loops for the the two states (waiting and dragging), an idea I got from Tomas Petricek's book "Real-world Functional Programming", but I ran into a problem:
与WPF或WinForms不同,Silverlight的MouseEventArgs不携带关于按钮状态的信息,因此我不能通过检查是否不再按下鼠标左键从拖动回路返回。我只是通过引入一个可变标志来解决这个问题。
Unlike WPF or WinForms, Silverlight's MouseEventArgs do not carry information about the button state, so I can't return from the drag-loop by checking if the left mouse button is no longer pressed. I only managed to solve this by introducing a mutable flag.
有没有人可以解决这个问题,这不涉及可变状态?
Would anyone have a solution for this, that does not involve mutable state?
以下是相关的代码部分(请原谅鼠标指针中的矩形拖动代码):
Here's the relevant code part (please excuse the sloppy dragging code, which snaps the rectangle to the mouse pointer):
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节中讨论。
The way to solve this issue is to use an overloaded AwaitEvent
that allows you to wait for two events. Instead of just waiting for MouseMove
, you can also wait for the MouseUp
event - in the first case, you can continue moving and in the second case, you can return from the loop and stop drag&drop (this is actually discussed later in the book in section 16.4.5).
这是代码 - 它实际上使用了一种方法(见下文)的一个更好的选择,因为它可以与 c> C> c> AwaitObservable code> Observable.map 和类似的组合器(以防您想使用这些组合器)。
Here is the code - it actually uses AwaitObservable
variant of the method (see below), which is a better choice in general, because it works with Observable.map
and similar combinators (in case you wanted to use these).
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()
As据我所知,F#库中尚未提供重载的 AwaitObservable
方法,但您可以从t 他的书的网站,或者你可以使用以下代码:
As far as I know, the overloaded AwaitObservable
method is not available in the F# libraries (yet), but you can get it from the book's web site, or you can use the following code:
// 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)
() ))
这篇关于使用F#和异步工作流在Silverlight中拖放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!