Created
September 6, 2016 12:44
-
-
Save FuNkNaN/09edf61d922ef9295f3c5c05614079b3 to your computer and use it in GitHub Desktop.
F# Event Handler using XAML markup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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=wpfApp" | |
xmlns:local="clr-namespace:ViewModels;assembly=wpfApp" | |
xmlns:fsxaml="http://github.com/fsprojects/FsXaml" | |
Height="300" Width="400" Background="LightGray" | |
Title="Handling Routed Events"> | |
<Window.DataContext> | |
<local:MainViewModel/> | |
</Window.DataContext> | |
<Window.Resources> | |
<Style TargetType="Grid"> | |
<Setter Property="funk:Tap.Handler" Value="{Binding TapHandler}"/> | |
</Style> | |
<Style TargetType="Button"> | |
<Setter Property="funk:Click.Handler" Value="{Binding ClickHandler}"/> | |
<Setter Property="Margin" Value="10"/> | |
</Style> | |
</Window.Resources> | |
<Grid Margin="0,10,0,0" | |
> | |
<Grid.RowDefinitions> | |
<RowDefinition Height="Auto"/> | |
<RowDefinition Height="Auto"/> | |
<RowDefinition/> | |
<RowDefinition Height="Auto"/> | |
<RowDefinition/> | |
</Grid.RowDefinitions> | |
<TextBlock Text="Clicking on the first or last Button" | |
TextWrapping="WrapWithOverflow" HorizontalAlignment="Center"/> | |
<TextBlock Grid.Row="1" Text="switches the Tap Event handler" | |
TextWrapping="WrapWithOverflow" HorizontalAlignment="Center"/> | |
<Button Grid.Row="2" Content="I'm here for starters"/> | |
<funk:MyButtonSimple Grid.Row="3" Content="Raise Tap Event" Width="100"/> | |
<Button Grid.Row="4" Content="I'm here for closure"/> | |
</Grid> | |
</Window> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace ViewModels | |
open FsXaml | |
open System.Windows | |
open FSharp.ViewModule | |
type MainView = XAML<"MainWindow.xaml"> | |
type MainViewModel() as self = | |
inherit ViewModelBase() | |
let onTapped1 = | |
let onTap sender (args : RoutedEventArgs) = | |
MessageBox.Show (sprintf "%A -> Bubble Up -> %A" args.OriginalSource sender) |> ignore | |
RoutedEventHandler(onTap) | |
let onTapped2 = | |
let onTap _ _ = MessageBox.Show "Not in the mood for bubbles" |> ignore | |
RoutedEventHandler(onTap) | |
let tapHandler = self.Factory.Backing(<@ self.TapHandler @>, onTapped1) | |
let toggle = ref false | |
let onClicked = | |
let onClick _ _ = | |
match !toggle with | |
| true -> tapHandler.Value <- onTapped1 | |
| false -> tapHandler.Value <- onTapped2 | |
toggle := not !toggle | |
MessageBox.Show "Handler switched" |> ignore | |
RoutedEventHandler(onClick) | |
member __.TapHandler | |
with get() = tapHandler.Value | |
and set(v) = | |
tapHandler.Value <- v | |
member __.ClickHandler = onClicked |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace funk | |
open System.Windows | |
open System.Windows.Controls | |
// http://stackoverflow.com/questions/39276618/custom-routed-event-in-f | |
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() | |
//http://stackoverflow.com/a/38817055/4838058 | |
type Click() = | |
inherit DependencyObject() | |
// For easy exchange | |
static let routedEvent = Button.ClickEvent | |
static let HandlerProperty = | |
DependencyProperty.RegisterAttached | |
( "Handler", typeof<RoutedEventHandler>, | |
typeof<Click>, new PropertyMetadata(null)) | |
static let OnEvent (sender : obj) args = | |
let control = sender :?> UIElement | |
let handler = control.GetValue(HandlerProperty) :?> RoutedEventHandler | |
if not <| ((handler, null) ||> LanguagePrimitives.PhysicalEquality) then | |
handler.Invoke(sender, args) | |
static do EventManager.RegisterClassHandler( | |
typeof<FrameworkElement>, routedEvent, | |
RoutedEventHandler(OnEvent)) | |
static member GetHandler (element: UIElement) : RoutedEventHandler = | |
element.GetValue(HandlerProperty) :?> _ | |
static member SetHandler (element: UIElement, value : RoutedEventHandler) = | |
element.SetValue(HandlerProperty, value) | |
type Tap() = | |
inherit DependencyObject() | |
// For easy exchange | |
static let routedEvent = MyButtonSimple.TapEvent | |
static let HandlerProperty = | |
DependencyProperty.RegisterAttached | |
( "Handler", typeof<RoutedEventHandler>, | |
typeof<Tap>, new PropertyMetadata(null)) | |
static let OnEvent (sender : obj) args = | |
let control = sender :?> UIElement | |
let handler = control.GetValue(HandlerProperty) :?> RoutedEventHandler | |
if not <| ((handler, null) ||> LanguagePrimitives.PhysicalEquality) then | |
handler.Invoke(sender, args) | |
static do EventManager.RegisterClassHandler( | |
typeof<FrameworkElement>, routedEvent, | |
RoutedEventHandler(OnEvent)) | |
static member GetHandler (element: UIElement) : RoutedEventHandler = | |
element.GetValue(HandlerProperty) :?> _ | |
static member SetHandler (element: UIElement, value : RoutedEventHandler) = | |
element.SetValue(HandlerProperty, value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment