Windows Phone 8: Moving Event Handlers into the base View class - wpf

I have a number of views in my Windows Phone 8 app that share a lot of similarity, so I created a base class to contain the common logic. In general, this approach has worked great, but with one limitation - I am unable to move the common event handling logic into the base class. Here is the simplified version of what I am trying to achieve:
The base class defines a method which my sub-classes should use to handle a button click event in their respective application bars.
public class BaseView : PhoneApplicationPage
{
protected void OnButtonClick(object sender, EventArgs e)
{
MessageBox.Show("Button Pressed");
}
}
The XAML for the inheriting view looks like this (showing only the relevant part). Note the ApplicationBarIconButton's event handler. My intention is that the OnButtonClick method, defined in the base view, is called.
<base:BaseView
x:Class="EventHandlersInBaseClassBugRepro.MainPage"
xmlns:base ="clr-namespace:EventHandlersInBaseClassBugRepro"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
..... >
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsMenuEnabled="False">
<shell:ApplicationBarIconButton
IconUri="/Assets/Tiles/FlipCycleTileSmall.png"
Text="Click"
Click="OnButtonClick"/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
The application compiles, but at runtime I am getting this exception:
{System.Windows.Markup.XamlParseException: Failed to assign to property 'Microsoft.Phone.Shell.ApplicationBarIconButton.Click'. [Line: 22 Position: 23]
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at EventHandlersInBaseClassBugRepro.MainPage.InitializeComponent()
at EventHandlersInBaseClassBugRepro.MainPage..ctor()}
I saw a similar question here Silverlight: Can I set an event to a base class event handler in XAML?. My interpretation of the answer suggests that the approach I am using should work, yet the exception.
Is what I am trying to do possible?

Remember Events are a delegate that should only be invoked in the class that declared them.
In your scenario you havent declared an Event in the BaseView.
Also mark the OnButtonClick invoke method as Virtual so that it can be overridden in derived classes. Try
public class BaseView : PhoneApplicationPage
{
public event EventHandler ButtonClicked;
public virtual void OnButtonClick(object sender, EventArgs e)
{
MessageBox.Show("Base Button Click");
}
}
In your derived class .cs you will need to override OnButtonClick like this
public override void OnButtonClicked(object sender, EventArgs e)
{
// do derived class logic here
MessageBox.Show("Derived class hit");
// calls BaseView event invoke method
base.OnButtonClicked(sender, e);
}
Hope that helps

Related

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

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.

WPF Control: where is "OnLoaded" virtual function?

In WinForm's control, there is an OnLoaded virtual function, but this seems to be missing in WPF control. I found this function very useful in some situations. For example, I could do something here after the control is "completely" initialized. In WPF control, there is an OnInitialized virtual function, but this function is called from InitializeComponent function which is too early and it doesn't allow derived class to setup. Is there any reason not to have this function in WPF? Or did I miss anything?
You can attach to the Loaded event of your Window object and do what you want to do inside the event handler (assuming you are using c#):
public MyWindow() //constructor
{
this.Loaded += MyWindow_Loaded;
}
private void MyWindow_Loaded(object sender, RoutedEventArgs e)
{
// do your stuff here
}
you will be looking for FrameworkElement.EndInit()
This will work after the initialization process of the Element...

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.

Capture Click Event in a Custom Control

I have a WPF Custom Control inherited from Button.
How do I programatically get the custom control to capture the Click Event (so that I can record the action and do some internal work)
(basically I want to catch the event and set a certain property to a certain value) and make this part of the classes standard functionality.
From my understanding the custom control should be able to catch it's own even and do some work.
Help appreciated
try one of the overrides
public class CustomButton : Button {
protected override void OnPreviewMouseDown(MouseButtonEventArgs e) {
base.OnPreviewMouseDown(e);
}
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) {
base.OnPreviewMouseLeftButtonDown(e);
}
}
I have realised why Ihad a problem.
I could not see the Click event
This was because I was not explicit enought in my class declaration:
I put
public class StateButton : Button
obviously picked the wrong button .. as
public class StateButton : System.Windows.Controls.Button
works
Then I just override the event
Thanks

WPF XAML Intellisense doesn't work correctly for custom routed event handlers

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 ?

Resources