我正在使用F#和ScottPlot,我需要用自己的内置右键单击事件替换ScottPlot。正如ScottPlot的网站所描述的(https://scottplot.net/faq/right-click-menu/),要做到这一点,我需要使用类似于formsPlot1.RightClicked -= formsPlot1.DefaultRightClickEvent;的东西来删除他们提供的DefaultRightClickEvent。
然而,F#不允许我这样做。没有‘删除’,我可以传递DefaultRightClickEvent给,除了‘添加’的信息表明,它是永久性的。我没有要使用的EventHandler,也不能从DefaultRightClickEvent中创建参数,因为它接受(obj * EventArgs)形式的参数,而不是obj -> EventArgs,而plot.RightClicked.RemoveHandler(new EventHandler(fun obj args -> plot.DefaultRightClickEvent(obj, args)))不工作。
这有可能吗?谢谢!
发布于 2022-07-18 17:43:20
最后,基本上按照MrD at KookerellaLtd的建议,我在C#项目中创建了绘图,删除了事件处理程序,并将修改后的绘图返回给F#代码。谢谢你的建议,但这是最干净的,特别是因为我正在做的这个项目已经有了C#组件。
发布于 2022-07-14 19:56:30
我从来没想过该怎么做,我不认为这是可能的。这就好像总是期望您能够创建您想要删除的任何事件处理程序。通常是这样的,这是我第一次看到这样的API,它将默认的处理程序公开为成员,然后建议您在不需要的情况下删除它--在C#中非常容易,但显然是F#中的一个问题(但是如果我错了,就有人纠正我!)
最简单的解决方案是处理情节的PreviewMouseRightButtonDown事件,显示您自己的上下文菜单(或其他什么),并将e.Handled设置为true。预览事件正是为了做这种事情而存在的。
(可能还有其他的解决办法。您可以尝试提交一个PR,添加一些公共方法,比如ClearDefaultMouseHandler(),这将清除处理程序,并且可以从F#调用)。
不要忘记Shift-F10应该是显示上下文菜单的标准热键。目前,ScottPlot并没有实现这个功能(至少我没有看到)。由于您想要控制上下文菜单,您应该意识到,在将来的某个时候,它可能支持该键组合,然后用户可能会通过打开默认上下文菜单而不是使用他们的键盘来给您惊喜。或者你想通过公关或者仅仅在你自己的代码中实现这一点。或者可能不是,因为如果你有多个情节,问题是哪一个有重点。只是一些需要注意的事情。
发布于 2022-07-14 22:30:17
问题是,C#使用直接指向fp.DefaultRightClickEvent方法的指针生成特定类型的EventHandler对象,因此删除事件的方法可以识别该方法并删除处理程序。
我不认为有一种方法可以在F#中生成这一点(目前),因为F#总是将方法引用包装到一个匿名lambda函数中。
恐怕我被这个问题吓了一跳--因为您当然可以查看生成的IL代码,并在运行时使用反射发射在F#中生成相同的内容。如果有任何其他的解决方案,这可能是要走的路:-),但事实证明,这实际上是可行的。
我有一个非常基本的表格,上面有一个情节:
let f = new System.Windows.Forms.Form()
let fp = new ScottPlot.FormsPlot()
f.Controls.Add(fp);以下代码生成一个动态委托,该委托以正确的方式调用事件的remove方法:
open System.Reflection.Emit
type A = class end
let remove = new DynamicMethod("Remove",typeof<System.Void>,[|typeof<obj>|],typeof<A>.Module)
let il = remove.GetILGenerator()
il.Emit(OpCodes.Ldarg_0)
il.Emit(OpCodes.Ldarg_0)
il.Emit(OpCodes.Ldftn, typeof<ScottPlot.FormsPlot>.GetMethod("DefaultRightClickEvent"))
il.Emit(OpCodes.Newobj, typeof<System.EventHandler>.GetConstructors()[0])
il.Emit(OpCodes.Callvirt, typeof<ScottPlot.FormsPlot>.GetEvent("RightClicked").RemoveMethod)
il.Emit(OpCodes.Ret)现在,你只需调用它,让处理程序被移除!
remove.Invoke(null, [| box fp |]) |> ignore我想我至少在C#中发现了一件比在F#中更容易做的事情!
https://stackoverflow.com/questions/72984833
复制相似问题