gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 02:43:05 24 4
gpt4 key购买 nike

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

我只是想在 Canvas 上围绕一个矩形拖动,对两种状态(等待和拖动)使用两个循环,这是我从 Tomas Petricek 的书“真实世界函数式编程”中得到的想法,但我跑了变成一个问题:

与 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# 库中不可用(目前),但您可以从 t he book's web site 获取它。 ,或者您可以使用以下代码:

// 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# 和异步工作流在 Silverlight 中拖放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2985783/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com