How does the WPF event system know about the event route? - wpf

I am trying to understand how RoutedEvents work.
Well - I walked through some tutorials and understood why RoutedEvents are useful and how they work.
But there is one thing, that I don't get:
Let's say I wrote a class (e.g. "MyClass") , which has a RoutedEvent property, sth. like this:
public class MyClass
{
public static readonly RoutedEvent myEvent;
...
}
Well - just giving a property is not enough - so I have to register the RoutedEvent with the help of EventManager:
...
myEvent = EventManager.RegisterRoutedEvent("MyEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyClass));
...
Okay - now the WPF event system knows about THIS event.
If I do it that way, each class I write will have it's own RoutedEvent. But that makes no sense to me.
What I want, is that other classes listen to the same event - without being a type of MyClass.
For example:
I have a stackpanel and within the stackpanel is a button. Clicking the stackpanel will raise the onClick event. Clicking the button will raise the onClick event of the button - and then the onClick event on the stackpanel.
But how?
Sorry - it's hard for me to describe the problem - I am just too confused :)
Thx a lot.
CodeCannibal

What I want, is that other classes listen to the same event - without being a type of MyClass.
You expect the right from this and this is what it delivers. I mean by registering a RoutedEvent you are not strongly binding it to the type; instead you are bridging it using the string "MyEvent" EventManager.RegisterRoutedEvent("MyEvent", ...
RoutedEvent traverse through the logical tree and stops traversing when handled (exceptions are there).
So, StackPanel need not to be derived from MyClass. You just need to register the RoutedEvent at StackPanel by specifying the action/handler. Whenever the RoutedEvent traverse through StackPanel it will call the corresponding action.
For example:
UserControl1.cs
//Routed Event
public static readonly RoutedEvent ThisIsEvent = EventManager.RegisterRoutedEvent("ThisIs", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(UserControl1));
// .NET wrapper
public event RoutedEventHandler ThisIs
{
add { AddHandler(ThisIsEvent, value); }
remove { RemoveHandler(ThisIsEvent, value); }
}
//local handler where RaiseEvent is called
private void button1_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ThisIsEvent));
}
And below is how you subscribe to that event in you XAML. You can also do this in your code file...
<StackPanel Orientation="Vertical" **local:UserControl1.ThisIs="StackPanel_ThisIs"** >
<local:UserControl1></local:UserControl1>
</StackPanel>
I hope this clear your doubts.

Related

Bind static method from another class as handler for WPF control event

I have a window, say MainWindow with some NumericUpDowns. I have another window MyCalculatorWindow like this:
public class MyCalculatorWindow : Window {
public static void LongUpDown_TouchUp(object sender, TouchEventArgs e)
{
// Show calculator and set numeric value when OK button is pressed.
}
// The rest of the MyCalculator functionality...
}
Is there a way to bind that static method to the TouchUp event handler property of LongUpDowns in xaml (ideally to all of them at once)? Something like this:
<xctk:LongUpDown TouchUp="{Binding Something??? MyCalculator.LongUpDown_TouchUp}" />
Is there a way to bind that static method to the TouchUp event handler property of LongUpDowns in xaml (ideally to all of them at once)? Something like this:
No, there isn't. The XAML compiler can only find event handlers in the same class as the element itself.
You could define a TouchUp event handler in the code-behind file for the view where the <xctk:LongUpDown /> element is and call the static method from there. It's a one-liner:
private void Window65_TouchUp(object sender, TouchEventArgs e) => MyCalculatorWindow.LongUpDown_TouchUp(sender, e);

Routed event from user control in MVVM application

I am stuck on integrating a user control into a mvvm application.
The user control is a custom calendar and was not wrtitten using MVVM principles (I don't want to re-write it in MVVM).
I have a mouse down event that is fired in the user control (Which is combination of three different user controls).
The event fired code looks like this:
public static readonly RoutedEvent DateEvent =
EventManager.RegisterRoutedEvent("dateEvent", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(UserControl2));
public event RoutedEventHandler dateEvent
{
add{AddHandler(DateEvent, value);}
remove{ RemoveHandler(DateEvent, value);}
}
private void UserControl_MouseUp(object sender, MouseButtonEventArgs e)
{
RaiseEvent(new RoutedEventArgs(UserControl2.DateEvent, this));
}
How do I subscribe to this routed event in my main app viewModel? I know it is not very MVVM but as I said I cant be doing with re-writing my user control.
I know that this event will bubble up the tree until it is marked as handled. I know to add a public void method to deal with the event - I'm just not sure how to implement the interception of the event in the first place.
I think you should read the RelayCommand section of this.
WPF MVVM Apps

What is the best way to handel click-events in MVVM?

What is the best way to handel click-events in MVVM? Are there a best way?
I have found two solutions:
with a relaycommand:
RelayCommand buttonAddCategory_Click;
public ICommand ButtonAddCategory_Click
{
get
{
return buttonAddCategory_Click ?? (buttonAddCategory_Click = new RelayCommand(param => this.AddCategory(),
param => true));
}
}
pro: ?; contra: need workaround with events if i would change ui elements like focus
with attached behaviour:
public static bool GetIsResetMouseLeftButtonDown(TreeView treeView)
{
return (bool)treeView.GetValue(IsResetMouseLeftButtonDownProperty);
}
public static void SetIsResetMouseLeftButtonDown(TreeView treeViewItem, bool value)
{
treeViewItem.SetValue(IsResetMouseLeftButtonDownProperty, value);
}
public static readonly DependencyProperty IsResetMouseLeftButtonDownProperty =
DependencyProperty.RegisterAttached("PreviewMouseLeftButtonDown", typeof(bool), typeof(TreeViewBehavior),
new UIPropertyMetadata(false, OnIsMouseLeftButtonDownChanged));
pro: you have RoutedEventArgs for changes on the ui; contra: access to other controls?
Right now i use both solutions. The RellayCommand in Buttons (with events for ui updates) and the attached behaviour for a treeview to deselect the treeviewitem if a user clicks.
To me there is no simple answer to this question.
That's the way I see it:
if you have a defined state-change on the VM, expose a RelayCommand which then can be bound to something the triggers it. In 99,9% percent of the cases this is a button/menu-entry. Something where it can be easily used. The cases that are left -> well some workaround might be needed, like calling a method from the view.
So a RelayCommand should imho be used if you are really targeting the VM.
Focus-changes on the other hand are view-related functionality. Imho this has nothing todo with the WM. That means for me it should be implemented in the view. So to me I'd even go for a straight-forward eventhandler that does the job.
hth,
Martin
I like this idea:
UI logic, such as opening new windows, showing/hiding elements, etc. You keep that on the code-behind.
When this 'click' should do something with the model, invoke the action.
So, a button that closes the window and saves something would be defined like this:
<Button Name="SaveBtnr" VerticalAlignment="Bottom"
Command="{Binding Save}" Click="OnSaveClick"
CommandParameter="{Binding}">Save</Button>
And the handler would be:
private void OnSaveClick(object sender, RoutedEventArgs e)
{
//Do UI Stuff
}
And then your command:
public void SaveCommand(object parameter)
{
//SaveStuff
}

Expose a Click event of a button inside a UserControl in Silverlight

I have a button inside my UserControl. I have three instances of this UserControl on the same page.
How can I expose the click event of the button inside such that I can assign different events for each instance of my UserControl.
I think this is similar to concept behind exposing DependencyProperty but I don't understand how to do it for events.
Thanks.
I normally add an event of the same name (and same parameters) to the user control and subscribe to the child control's original event, so I can pass the event on:
public partial class ClickEventControl : UserControl
{
public event EventHandler<RoutedEventArgs> Click;
public ClickEventControl()
{
InitializeComponent();
}
private void aButton_Click(object sender, RoutedEventArgs e)
{
if (Click != null)
{
Click(sender, e);
}
}
}
I would also be interested if there is a more general way of doing it.

WPF Custom Routed event question

How do you get two unrelated controls to raise the same custom event? All examples I have seen so far have an event defined within a single control, should I be taking a different approach?
Eg. I'd like to raise a custom bubbling event from an OnFocus handler for a button and a textbox.
First off let me say your question doesn't make it clear that you don't want to use the existing UIElement.GotFocusEvent, but I'll assume you know about it and have your reasons for not using it.
You can always register a custom event on a static class, and raise it wherever you want. The Keyboard class does with all of its events (e.g. Keyboard.KeyDownEvent).
public static class RoutedEventUtility
{
public static readonly RoutedEvent MyCustomEvent = EventManager.RegisterRoutedEvent("MyCustomEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(RoutedEventUtility));
}
You raise the event just like you would any other RoutedEvent.
RoutedEventArgs args = new RoutedEventArgs(RoutedEventUtility.MyCustomEvent);
RaiseEvent(args);
If you want another class to own the event as a public field then you will need to add an owner.
public class MyCustomControl : Control
{
public static readonly RoutedEvent MyCustomEvent = RoutedEventUtility.MyCustomEvent.AddOwner(typeof(MyCustomControl));
}

Resources