F#中的自定义路由事件

3
我正在尝试翻译这段C#代码。目前我的翻译如下:
type MyButtonSimple() as self =
    inherit Button()

    static let TapEvent =
        EventManager.RegisterRoutedEvent
            ( "Tap", RoutingStrategy.Bubble, 
              typeof<RoutedEventHandler>, typeof<MyButtonSimple>)

    let tapEvent = new Event<RoutedEventHandler, RoutedEventArgs>()
    let raiseTapEvent() =
        let newEventArgs = new RoutedEventArgs(TapEvent)
        tapEvent.Trigger(self, newEventArgs)

    [<CLIEvent>]
    member x.Tap = tapEvent.Publish 

    // For demonstration purposes we raise the event when clicked
    override self.OnClick() =
        raiseTapEvent()

MainWindow.xaml

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:funk="clr-namespace:funk;assembly=appWPF"
    Title="Routed" Height="300" Width="400">
    <StackPanel Background="LightGray">
        <funk:MyButtonSimple Content="Spin" Background="#808080" Foreground="LightGray">
            <funk:MyButtonSimple.RenderTransform>
                <TransformGroup>
                    <RotateTransform x:Name="rotate"/>
                </TransformGroup>
            </funk:MyButtonSimple.RenderTransform>
            <funk:MyButtonSimple.Triggers>
                <EventTrigger RoutedEvent="funk:MyButtonSimple.Tap">
                    <BeginStoryboard>
                        <Storyboard RepeatBehavior="Forever">
                            <DoubleAnimation 
                                Storyboard.TargetName="rotate"
                                Storyboard.TargetProperty="Angle"
                                From="0" To="90" Duration="0:0:2"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </funk:MyButtonSimple.Triggers>
        </funk:MyButtonSimple>
    </StackPanel>
</Window>

点击按钮不会启动动画。

将代码 RoutedEvent="funk:MyButtonSimple.Tap" 更改为 RoutedEvent="GotFocus" 就可以得到一个可工作的示例(Button.Click被覆盖)。

有什么想法吗?


你尝试过简单地写<EventTrigger RoutedEvent="Tap">吗? - Filippo Vigani
@Filippo 是的,那也不起作用。未从FrameworkElement或UIElement继承的事件必须指定,例如Button.Click。 - Funk
2
尝试将“静态成员”替换为“静态常量”。 - Marko Grdinić
@Marko 谢谢!这样就解决了错误。我更新了我的问题。 - Funk
1个回答

3

这很棘手,因为它在F#中做了许多非标准的事情。

该C#代码的翻译如下:

type MyButtonSimple() as self =
    inherit Button()

    static let tapEvent = 
       EventManager.RegisterRoutedEvent
            ( "Tap", RoutingStrategy.Bubble, 
              typeof<RoutedEventHandler>, typeof<MyButtonSimple>)

    // Create a custom event so you can override AddHandler/RemoveHandler behavior
    let tapEvent = 
        { new IDelegateEvent<RoutedEventHandler> with
            member this.AddHandler del = self.AddHandler(MyButtonSimple.TapEvent, del)
            member this.RemoveHandler del = self.RemoveHandler(MyButtonSimple.TapEvent, del) }

    // Raise via routed eventing strategy
    let raiseTapEvent() =
        let newEventArgs = new RoutedEventArgs(MyButtonSimple.TapEvent)
        self.RaiseEvent newEventArgs

    // This isn't exactly the same, but public static fields aren't allowed in F#, and
    // this works for WPF
    static member TapEvent with get() = tapEvent  

    [<CLIEvent>]
    member x.Tap = tapEvent

    // For demonstration purposes we raise the event when clicked
    override self.OnClick() =
        raiseTapEvent()

主要的注意点是,你需要覆盖标准事件行为,这需要自己实现 IDelegateEvent 而不是使用正常的 F#事件管理。此外,在 F# 中无法使用 public static readonly 字段,因此将事件包装到属性中。尽管这不是实现路由事件的“标准”方式,但 WPF 似乎可以接受。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接