如果有办法将XAML中定义的事件挂钩到成员的F#函数,我会徘徊吗?当然,我可以用图解方式来做,但它有点不方便。
答案 0 :(得分:9)
我想问的是你是否可以使用XAML标记将F#成员指定为事件处理程序:
<Button x:Name="btnClick" Content="Click!" Click="button1_Click" />
据我所知,答案是否。
这在C#中的工作方式是事件处理程序的注册是在设计者生成的C#代码(部分类)中完成的(您可以在名为{{1}的文件的obj
目录中看到})。 F#对WPF设计器没有任何直接支持,因此无法为您生成此内容。你必须编写代码来手动附加事件处理程序(但这很容易)。
我的London talk about Silverlight中有一些例子。您可以实现MainForm.g.cs
运算符以获得对XAML元素的良好访问:
?
我使用的 type MainPage() as this =
inherit UserControl()
let uri = new System.Uri("/App;component/MainPage.xaml", UriKind.Relative)
do Application.LoadComponent(this, uri)
// Get button using dynamic access and register handler
let btn : Button = this?btnClick
do btnClick.Click.Add(fun _ -> (* ... *))
运算符声明是:
?
答案 1 :(得分:4)
可以为命令添加绑定,例如。使用按钮中的Command =“...”属性。
所以在你的XAML中你可以拥有:
<Button Command="{Binding MyCommandHandler}">
然后在您的ViewModel代码中,如果您有一个名为MyCommandHandler的成员,它将被绑定到上面的按钮。所以在你的F#中,有类似的东西:
module ViewModel =
type FuncCommand (canExec:(obj -> bool), doExec:(obj -> unit)) =
let theEvent = new DelegateEvent<EventHandler>()
interface ICommand with
[<CLIEvent>]
member x.CanExecuteChanged = theEvent.Publish
member x.CanExecute arg = canExec(arg)
member x.Execute arg = doExec(arg)
type MyViewModel() =
member this.MyCommandHandler =
new FuncCommand(
(fun _ -> ... SOME CODE WHICH RETURNS TRUE OR FALSE ...),
(fun _ -> ... SOME CODE TO HANDLE THE CLICK ...)
)
答案 2 :(得分:2)
您可以使用附加属性来执行此操作:
;
--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3
ORDER BY ( SELECT 0)) RN
FROM #MyTable)
DELETE FROM cte
WHERE RN > 1;
然后在xaml中使用它:
namespace Foo
open System.Windows
open System.Windows.Controls
open System.Windows.Controls.Primitives
open System.Windows.Media
module Register =
// http://stackoverflow.com/a/14706890/1069200
type internal Marker = interface end
let ClickHandlerProperty = DependencyProperty.RegisterAttached(
"ClickHandler",
typeof<RoutedEventHandler>,
typeof<Marker>.DeclaringType,
PropertyMetadata(null))
let SetClickHandler (element: UIElement, value : RoutedEventHandler) =
element.SetValue(ClickHandlerProperty, value)
let GetClickHandler (element: UIElement) : RoutedEventHandler =
element.GetValue(ClickHandlerProperty) :?> _
let private OnClick (sender : obj) args =
let button = sender :?> UIElement
let handler = GetClickHandler button
if not (obj.ReferenceEquals(handler, null)) then
handler.Invoke(sender, args)
let private initialize =
EventManager.RegisterClassHandler(
typeof<FrameworkElement>,
ButtonBase.ClickEvent,
RoutedEventHandler(OnClick))
栏位于:
<Window ...
xmlns:foo="clr-namespace:Foo;assembly=Foo">
<Button Content="Click!" foo:Register.ClickHandler="{x:Static foo:Bar.OnClicked}" />
</Window>
我不知道f#所以上面的代码可能会被清理很多。
对于click事件,David建议绑定命令可能是最好的。
答案 3 :(得分:1)
现在FsXaml的较新版本支持此版本,但它与C#中的版本略有不同。
使用FsXaml,您可以定义Xaml并指定事件处理程序。例如,在名为&#34; MyWindow&#34;的窗口中,您可以执行以下操作:
<Button Content="Click!" Click="button1_Click" />
在您的&#34;代码背后&#34;文件,你会这样处理:
type MyWindowBase = XAML<"MyWindow.xaml">
type MyWindow () =
inherit MyWindowBase
override this.button1_Click (_,_) = () // Handle event here