C
C#•3y ago
Bin

WPF cannot capture custom event using Microsoft.Xaml.Behaviors.Wpf (solved)

Suppose i have a project that raise an event. When i click on a button, obviously "Click" event will be raised. Inside the click handler method, i raised a custom event called "FileOpen" event. I have successfully captured "Click" event by testing whether MessageBox popped or not. However, it fails to capture "FileOpen" custom event, it doesn't pop another MessageBox that tells "FileOpen event captured". I'm guessing its because i put the wrong name (maybe wrong format, e.g must be fully qualified name or so) in the XAML of line <i:EventTrigger EventName="FileOpen">. So how do i capture this custom event? XAML for the button:
<Button x:Name="MyButton" Content="Click to fire FileOpen event">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding ClickCommand}"/>
</i:EventTrigger>

<i:EventTrigger EventName="FileOpen">
<i:InvokeCommandAction Command="{Binding FileOpenCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button x:Name="MyButton" Content="Click to fire FileOpen event">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding ClickCommand}"/>
</i:EventTrigger>

<i:EventTrigger EventName="FileOpen">
<i:InvokeCommandAction Command="{Binding FileOpenCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
11 Replies
Bin
BinOP•3y ago
Code behind for this XAML (for sake of this question, ignore the fact its not using viewmodel)
public partial class CustomEventDemo : Window
{
public CustomEventDemo()
{
InitializeComponent();
DataContext = this;
ClickCommand = new RelayCommand(OnClick);
FileOpenCommand = new RelayCommand(OnFileOpen);
}

// Events -----------------------------------------------------------------

public static readonly RoutedEvent FileOpenEvent
= EventManager.RegisterRoutedEvent(
nameof(FileOpen),
RoutingStrategy.Bubble,
handlerType: typeof(RoutedEventHandler),
ownerType: typeof(CustomEventDemo));

public event RoutedEventHandler FileOpen
{
add { AddHandler(FileOpenEvent, value); }
remove { RemoveHandler(FileOpenEvent, value); }
}

// Commands ---------------------------------------------------------------

public ICommand ClickCommand { get; }
private void OnClick(object? arg)
{
MessageBox.Show("Button click event captured");
MyButton.RaiseEvent(new RoutedEventArgs(FileOpenEvent));
}

public ICommand FileOpenCommand { get; }
private void OnFileOpen(object? arg)
{
MessageBox.Show("FileOpen event captured");
}
}
public partial class CustomEventDemo : Window
{
public CustomEventDemo()
{
InitializeComponent();
DataContext = this;
ClickCommand = new RelayCommand(OnClick);
FileOpenCommand = new RelayCommand(OnFileOpen);
}

// Events -----------------------------------------------------------------

public static readonly RoutedEvent FileOpenEvent
= EventManager.RegisterRoutedEvent(
nameof(FileOpen),
RoutingStrategy.Bubble,
handlerType: typeof(RoutedEventHandler),
ownerType: typeof(CustomEventDemo));

public event RoutedEventHandler FileOpen
{
add { AddHandler(FileOpenEvent, value); }
remove { RemoveHandler(FileOpenEvent, value); }
}

// Commands ---------------------------------------------------------------

public ICommand ClickCommand { get; }
private void OnClick(object? arg)
{
MessageBox.Show("Button click event captured");
MyButton.RaiseEvent(new RoutedEventArgs(FileOpenEvent));
}

public ICommand FileOpenCommand { get; }
private void OnFileOpen(object? arg)
{
MessageBox.Show("FileOpen event captured");
}
}
undisputed world champions
you are listening for the FileOpen event on the button, but its your windows CustomEventDemo that has FileOpen event 😉
Bin
BinOP•3y ago
yeah i know i am raising the FileOpen event on the button, but since its a bubbling event, it should also raise (or travel) to the windows right? srry for late reply
Bin
BinOP•3y ago
routing strategy = bubble
Bin
BinOP•3y ago
maybe i misunderstood how things work
Bin
BinOP•3y ago
i fired the FileOpenEvent on the button itself when button clicked as you can see in the code-behind screenshot, then i tried to capture that event inside the button itself and on the grid to see if my Microsoft.Xaml.Behaviors.Wpf bubbling behaviour is working. I do this because i want to handle my events inside my viewmodel (following MVVM pattern), but when i tried to capture the event without using Microsoft.Xaml.Behaviors.Wpf by directly handling it in the view (e.g <Button FileOpen="HandlerName">) it works flawlessly
Bin
BinOP•3y ago
well, my Microsoft.Xaml.Behaviors.Wpf can capture event for builtin events, but for custom like mine does not
Bin
BinOP•3y ago
as you can see, it works if i dont handle my event through Microsoft.Xaml.Behaviors.Wpf (by handling it using code-behind), but it's ugly, i want to follow MVVM pattern
undisputed world champions
oh i somehow missed the use of attached event :/ i dont think this is supported out-of-the-box, but check this out: https://github.com/microsoft/XamlBehaviorsWpf/issues/110 basically create your own RoutedEventTrigger:
public class RoutedEventTrigger : EventTriggerBase<FrameworkElement>
{
RoutedEvent _routedEvent;
public RoutedEvent RoutedEvent
{
get { return _routedEvent; }
set { _routedEvent = value; }
}

public RoutedEventTrigger() { }

protected override void OnAttached()
{
if (RoutedEvent != null)
{
Source.AddHandler(RoutedEvent, new RoutedEventHandler(this.OnRoutedEvent));
}
}

void OnRoutedEvent(object sender, RoutedEventArgs args)
{
base.OnEvent(args);
}
protected override string GetEventName()
{
return RoutedEvent.Name;
}
}
public class RoutedEventTrigger : EventTriggerBase<FrameworkElement>
{
RoutedEvent _routedEvent;
public RoutedEvent RoutedEvent
{
get { return _routedEvent; }
set { _routedEvent = value; }
}

public RoutedEventTrigger() { }

protected override void OnAttached()
{
if (RoutedEvent != null)
{
Source.AddHandler(RoutedEvent, new RoutedEventHandler(this.OnRoutedEvent));
}
}

void OnRoutedEvent(object sender, RoutedEventArgs args)
{
base.OnEvent(args);
}
protected override string GetEventName()
{
return RoutedEvent.Name;
}
}
and use it as your event trigger:
<local:RoutedEventTrigger RoutedEvent="{x:Static local:CustomEventDemo.FileOpenEvent}">
<i:InvokeCommandAction Command="{Binding FileOpenCommand}"/>
</local:RoutedEventTrigger>
<local:RoutedEventTrigger RoutedEvent="{x:Static local:CustomEventDemo.FileOpenEvent}">
<i:InvokeCommandAction Command="{Binding FileOpenCommand}"/>
</local:RoutedEventTrigger>
GitHub
[EventTrigger]Support for Attached Event? · Issue #110 · microsoft/...
Is your feature request related to a problem? Please describe. I&#39;m using an attached event on a Border. public class ClickExtensions { public static readonly RoutedEvent ClickEvent = EventM...
Bin
BinOP•3y ago
oh wow it works. I dont know why it works though because i am new to WPF, at least it does exactly what i want. I will study depper about WPF such as frameworkelement and such eventually. Tysm man, you saved my life ez i really appreciate that you spend your time here for helping me
Bin
BinOP•3y ago
Currently this is how i do to handle events, by capturing it with the view, then i pass it to the viewmodel. I definitely will refactor my code using commands after known this technique
Want results from more Discord servers?
Add your server