【问题标题】:Where does UIElement.add_MouseDown come from in f#?f# 中的 UIElement.add_MouseDown 来自哪里?
【发布时间】:2012-09-15 06:37:32
【问题描述】:

我试图了解为什么以下代码有效(取自http://jyliao.blogspot.com/2007/10/learning-wpf.html):

open System
open System.Windows
open System.Windows.Input

(* From Chap 1 - HandleAnEvent.cs *)
let WindowOnMouseDown sender (args:MouseButtonEventArgs) =
   let win = unbox<Window> sender
   let str = sprintf "Window clicked with %A button at point (%A)" args.ChangedButton (args.GetPosition win)
   MessageBox.Show(str)|>ignore

let win = new Window()
win.Title <- "Handle an Event"
win.add_MouseDown(new MouseButtonEventHandler(WindowOnMouseDown))

#if COMPILED
[<STAThread()>]
do 
    let app =  new Application() in
    app.Run(win) |> ignore
#endif

我不明白的部分是对add_MouseDown 的调用。当我将鼠标悬停在 VS 中的调用上时,它告诉我该方法来自 UIElement 类,但我在 .NET 类库中找不到对该方法的任何引用。

在 F# 中,我希望调用是:

win.MouseDown.AddHandler (new MouseButtonEventHandler(WindowOnMouseDown))

当我进行此更改时,弹出的消息框不再显示您单击的窗口内的坐标。相反,它显示的坐标与窗口内鼠标单击的位置无关,但会随着您在屏幕上移动窗口而改变。因此,sender 参数似乎指的是窗口以外的某些 UI 元素。

有谁明白为什么使用 add_MouseDown 有效(以及该方法的存在记录在哪里),以及为什么使用 AddHandler 无效?

我正在使用 VS2010、F# 2.0、.NET 3.0 库。

更新:

啊,我刚刚意识到使用 AddHandler 与使用 add_MouseDown 的工作方式不同,我是错误。我实际上一直在做的是使用两种不同的方法一个接一个地添加两个事件处理程序:

win.add_MouseDown(new MouseButtonEventHandler(WindowOnMouseDown))
win.MouseDown.AddHandler (new MouseButtonEventHandler(WindowOnMouseDown))

这会弹出两个消息窗口,第一个显示窗口内的正确位置,第二个显示另一个愚蠢的位置。但如果我真的将 add_MouseDown 调用替换为 addHandler 调用,那么我会得到相同的结果。

所以对于这一部分,我认为我真正的问题是为什么第二个事件处理程序报告不同的位置。但也许这最好作为一个单独的问题来处理。

【问题讨论】:

  • 添加类型注解是否有效:(sender: obj)?事实上,函数是泛型的,与MouseButtonEventHandler的类型不匹配。
  • 您的代码有一些问题:(1) string.Format 无法在 F# 中编译 (2) 您没有使用 sender(除了将其存储在 win 中) .
  • @Daniel (1) 哎呀,我在我的代码中更改了它,但在创建问题时直接从网站复制,只是在上面更改它 (2) 不正确,win 传递给 GetPosition跨度>

标签: wpf f#


【解决方案1】:

我不确定为什么它不起作用,但您可以通过将闭包传递给 Add 来完成同样的事情:

let win = Window()
win.MouseDown.Add(fun args ->
  let str = sprintf "Window clicked with %O button at point (%O)" args.ChangedButton (args.GetPosition(win))
  MessageBox.Show(str) |> ignore)

现在很清楚win 指的是什么(无需拆箱)。无论如何,这比无类型的 sender 参数要好。也许它会按预期工作?

【讨论】:

  • 是的,这很好用(只要它是唯一的事件处理程序 - 请参阅上面的更新)。
【解决方案2】:

add_MouseDownMouseDown 事件的 add 访问器的名称。
在C#中,这个方法是通过写win.MouseDown += ...来调用的。
在 VB.Net 中,调用方式为AddHandler(win, AddressOf ...)

F# 没有用于添加事件处理程序的特殊语法,因此您需要显式调用它。

【讨论】:

  • "F# 没有用于添加事件处理程序的特殊语法" 确实有 -- Event.add
  • 你知道我在哪里可以找到这方面的文档吗?即,在哪里记录了事件的 add 访问器对应于 f# 中的 add_event 方法?请注意,VS 中的智能感知不显示此方法,这看起来很奇怪,因为它似乎确实存在。你明白为什么使用 AddHandler 会导致不同的行为吗?
  • 更重要的是,F#不需要添加事件处理程序的特殊语法,因为事件只是对象,具有AddHandler 之类的方法。这很酷,因为您可以将它们用作函数的参数,因此 .NET Rx 之类的东西变得更好!
猜你喜欢
  • 2010-09-21
  • 2014-04-24
  • 2015-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多