拖放Silverlight中使用F#和异步工作流 [英] 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.
我只是试图拖动画布上的一个矩形,用两个循环的两种状态(等待并拖动),一个想法,我从托马斯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不携带有关按钮状态的信息,这样我就可以从拖动循环通过检查鼠标左键不再是pressed不归。我只设法通过引入可变标志,以解决这个问题。
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?
下面是有关的code部分(请原谅马虎拖拉code,它捕捉矩形鼠标指针):
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())
()
非常感谢您的时间!
Thank you very much for your time!
推荐答案
解决这个问题的方法是使用一个重载 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).
下面是code - 它实际上使用的方法 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()
据我所知,重载 AwaitObservable
方法不是在F#库(还),但您可以从弄不明白的他的书网站,或者您可以使用下面的code:
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)
() ))
这篇关于拖放Silverlight中使用F#和异步工作流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!