Please check the code below which defines the same scroll event in two different ways:
---------------------------------normal way--------------------------------------
public event RoutedEventHandler CloseTab;
------------------------------static RoutedEvent---------------------------------
public static readonly RoutedEvent CloseTabEvent =
EventManager.RegisterRoutedEvent("CloseTab", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(CloseableTabItem));
public event RoutedEventHandler CloseTab
{
add { AddHandler(CloseTabEvent, value); }
remove { RemoveHandler(CloseTabEvent, value); }
}
1.What's the difference between the normal customized event and the static RoutedEvent?
2.Why the event in the first way can be raised by a method like "if(CloseTab!=null){CloseTab(o,e);}",but in the second way ,it only can be raised by the UIElement.RaiseEvent() method?
3.I know this question must be very very silly,but it dose make me confused.
It is that Why the event in the first way can be raised by the "if(CloseTab!=null){CloseTab(o,e);}" method only in the class which the event is defined?And when it is outside the owner class,the event can only add or remove handlers with "+=/-=" ?
Thanks for your time!!
You implementation basics i.e. the way we raise each one differently, are correct.
But apart from that, as far as my knowldge on routed events goes...
The first is NOT a routed event. It is a simple CLR event declared with its type as the RoutedEventHandler delegate. When this event is raised it will not bubble \ tunnel up to the ancestor/child UI elements respectively.
At practical level, I guess if you try using the first one in EventTrigger it will not work.
Related
I will appreciate if some body can explain with a simple example.
Imagine a Window containing a dense hierarchy of child controls. Now let's say you want to do something, there's a right click anywhere in your window.
With normal events, you'd have to handle a Click event for all controls, because you're not sure where the user might click.
With WPF's routed events, the events either "bubble" or "tunnel" (i.e travel up the UI tree or down) if they dont find an event handler, which "handles" it at the current level. So you could write one handler for the window's event i.e. TopLevel. (WPF has a convention of event pairs, PreviewXXX and XXX - the PreviewXXX event fires first and tunnels down from root to control which received the stimulus and the counterpart XXX event then bubbles up from child control back upto Root). So if you right click a button, WPF travels up the UI hierarchy, invoking all handlers that it finds (unless someone marks the event has "handled" in the event args.)
Routed events are events with more 'traveling abilities', as mentioned in a Gishu's answer. Routed events are represented by an instance of a RoutedEvent class + ordinary .NET event, which wraps it:
public class MyClassWithARoutedEvent : UIElement
{
public static readonly RoutedEvent DoSomethingEvent;
public event RoutedEventHandler DoSomething
{
add { base.AddHandler ( MyClassWithARoutedEvent.DoSomethingEvent, value );
remove { base.AddHandler ( MyClassWithARoutedEvent.DoSomethingEvent, value );
}
}
You would typically use touted events in such situations:
Implementing your own control which seamlessly integrates with WPF's infrastructure
Processing events, fired by different controls at a common root
Sort of communication between elements in an element tree
In most situations you will probably use the routed events infrastructure without even noticing it.
In addition it's worth to mention, that you can use RoutedEvent in your control even if it does not define it or even inherits from an element, which does. That's because you can really think about a RoutedEvent instance as a strong typed name of an event. So, if you have an access to this 'name' (this is why an instance of a routed event is usually made public), you can owe it:
public class MyClassWithARoutedEvent : UIElement
{
public static readonly RoutedEvent ClickEvent;
static MyClassWithARoutedEvent ( )
{
ClickEvent = ButtonBase.ClickEvent.AddOwner( typeof ( MyClassWithARoutedEvent ) );
}
// A wrapper should be placed here as described above
}
I need to add an event handler to an inherited control like a datagridview but Visual Studio doesn't allow me. Isn't there a way for an inherited control to fire a base event handler AND the inherited one? in a sequence I specify?
Your question is unclear. Assuming that you're trying to handle the base class' event in the inherited control, you can override the OnEventName protected virtual method. In the override, make sure to call the base method or the event won't fire.
This method exists (AFAIK) for every event in every control in System.Windows.Forms. If the control you're inheriting does not have this virtual method, you can subscribe to the vent in the constructor.
For example:
class MyButton : Button {
//First way
protected override void OnClick(EventArgs e) {
base.OnClick(e); //Without this line, the event won't be fired
//...
}
//Second way
public MyButton() {
base.Click += Base_Click;
}
void Base_Click(object sender, EventArgs e) {
//...
}
}
EDIT:
If you're trying to raise the base class' event, you can call these OnEventName methods.
If the base class doesn't have one, the only way to do it is to declare a new event, and add a handler to the original event from the base class that raises your new event. Note that if you have other code that uses the base class' event, and the evnet is not virtual and doesn't have a raiser method, you're out of luck, unless you can decompile the base clas and find out where the event is raised.
Events in WinForms typically have a corresponding "On*" method. Simply call that method, and it'll raise the event. If you want to raise "CellClick" for example, call "base.OnCellClick(new DataGridViewCellEventArgs(row, column))".
I defined a custom routed event with the following constructs (names changed):
public class MyRoutedEventArgs : RoutedEventArgs
{...}
public delegate void MyRoutedEventHandler(Object sender, MyRoutedEventArgs args);
public static readonly RoutedEvent MyEvent;
MyClass.MyEvent =
EventManager.RegisterRoutedEvent("MyEvent", RoutingStrategy.Tunnel, typeof(MyRoutedEventHandler), typeof(MyClass));
Next, I'm creating a CLR event wrapper:
public event MyRoutedEventHandler MyEvent {
add { AddHandler(MyEvent, value); }
remove { RemoveHandler(MyEvent, value); }
}
The problem is when I define it as shown above, XAML intellisense doesn't work for autogenerating the handler method body. What I noticed is that if you change your CLR event wrapper to use generic RoutedEventHandler type, everything works! However in this case, the auto-generated method gets a generic RoutedEventArgs (well, correctly corresponding to RoutedEventHandler), which forces me to manually rewrite it as MyRoutedEventArgs.
I think this is currently a limitation you have to live with. But all you have to do is, once the eventhandler for the generic type was autogenerated, change the signature of the generated method to use MyRoutedEventArgs instead of RoutedEventArgs. Allthough still ugly (we shouldn't be forced to do this) I would think it is not such a big problem.
Anyone tried it with VS 2010 ?
Anyone know how to create a routed event in Silverlight 2? In WPF, the code would be like below. However, there’s no EventManager in Silverlight.
public static readonly RoutedEvent ShowVideoEvent =
EventManager.RegisterRoutedEvent("ShowVideo", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(NavBar));
public event RoutedEventHandler ShowVideo
{
add { AddHandler(ShowVideoEvent, value); }
remove { RemoveHandler(ShowVideoEvent, value); }
}
At least for the time being, there doesn't seem to be a way to create your own. That post was however for Beta2, looking at the document for Beta2->RC0 breaking changes, there doesn't seem to be any mention of anything. But then I guess it could be no breaking change, we can always hope eh ;)
There are a number of events which are routed but again I'm not sure this documentation has been updated for RC0.
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));
}