Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
swdev:dotnet:events [2012/11/01 14:42] smayr [Example] |
swdev:dotnet:events [2015/06/15 15:28] (current) ajdavis [Routed Events] |
||
---|---|---|---|
Line 164: | Line 164: | ||
== Routed Events == | == Routed Events == | ||
- | In WPF, you also have access to Routed Events, which have additional advantages. | + | In WPF, you also have access to Routed Events, which have additional advantages. |
RoutedEvents are particularly useful if the listener doesn' | RoutedEvents are particularly useful if the listener doesn' | ||
Line 174: | Line 174: | ||
Writing a custom routed event is similar to writing a dependency property, | Writing a custom routed event is similar to writing a dependency property, | ||
<code csharp> | <code csharp> | ||
- | public static readonly RoutedEvent | + | public static readonly RoutedEvent |
- | " | + | " |
| | ||
| | ||
Line 181: | Line 181: | ||
// Provide CLR property wrapper for the routed event | // Provide CLR property wrapper for the routed event | ||
- | public event RoutedEventHandler | + | public event RoutedEventHandler |
{ | { | ||
- | add { AddHandler(MyRoutedEvent, value); } | + | add { AddHandler(OnMyActionEvent |
- | remove { RemoveHandler(MyRoutedEvent, value); } | + | remove { RemoveHandler(OnMyActionEvent |
} | } | ||
+ | |||
+ | // Method to raise event | ||
+ | public void RaiseMyActionEvent() | ||
+ | { | ||
+ | RaiseEvent(new RoutedEventArgs(MyControl.OnMyActionEvent )); | ||
+ | } | ||
+ | |||
</ | </ | ||
The tunneling and bubbling of a routed event occurs when every element in the route exposes that event. But WPF supports tunneling and bubbling of routed events through elements that don’t even define that event – this is possible via attached properties. Attached events operate much like attached properties (and their use with tunneling or bubbling is very similar to using attached properties with property value inheritance), | The tunneling and bubbling of a routed event occurs when every element in the route exposes that event. But WPF supports tunneling and bubbling of routed events through elements that don’t even define that event – this is possible via attached properties. Attached events operate much like attached properties (and their use with tunneling or bubbling is very similar to using attached properties with property value inheritance), | ||
- | **Attached | + | **Attached |
<code xml> | <code xml> | ||
<Grid Button.Click=" | <Grid Button.Click=" | ||
Line 199: | Line 206: | ||
Grid doesn’t have a Click event, but WPF allows the Button.Click event to be raised on the Grid. The Grid can then handle this event in it’s handler “ButtonClickHandler”. Every routed event can be used as an attached event. We can also hook up the attached event in code, | Grid doesn’t have a Click event, but WPF allows the Button.Click event to be raised on the Grid. The Grid can then handle this event in it’s handler “ButtonClickHandler”. Every routed event can be used as an attached event. We can also hook up the attached event in code, | ||
- | **Attached | + | **Attached |
<code xml> | <code xml> | ||
<Grid x: | <Grid x: | ||
Line 214: | Line 221: | ||
{ | { | ||
// do something | // do something | ||
+ | . . . | ||
+ | e.Handled = true; // mark event as handled so other listeners do try to handle it as well | ||
} | } | ||
</ | </ | ||
- | Raise Event: | + | |
- | <code csharp> | + | |
- | // Somewhere the event gets triggered | + | |
- | ... | + | |
- | // Raise the routed event " | + | |
- | RaiseEvent(new RoutedEventArgs(Button.Click)); | + | |
- | </ | + | |
=== Example === | === Example === | ||
'' | '' | ||
Line 307: | Line 310: | ||
// Attach menu event handler | // Attach menu event handler | ||
- | popupmnu1.MenuItemSelected += new RoutedEventHandler(ucPopupMnu_MenuItemSelected); | + | |
+ | // or | ||
+ | AddHandler(ucPopupMnu.MenuItemSelectedEvent, | ||
} | } | ||
Line 373: | Line 378: | ||
} | } | ||
</ | </ | ||
+ | === Example of Custom RoutedEvent === | ||
+ | |||
+ | UserNotification logic is composed of a u'' | ||
+ | |||
+ | UserControl for UserNotification event trigger. | ||
+ | '' | ||
+ | <code xml> | ||
+ | < | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | <code csharp> | ||
+ | using System; | ||
+ | using System.Collections.Generic; | ||
+ | using System.Linq; | ||
+ | using System.Text; | ||
+ | using System.Windows; | ||
+ | using System.Windows.Controls; | ||
+ | using System.Windows.Data; | ||
+ | using System.Windows.Documents; | ||
+ | using System.Windows.Input; | ||
+ | using System.Windows.Media; | ||
+ | using System.Windows.Media.Imaging; | ||
+ | using System.Windows.Navigation; | ||
+ | using System.Windows.Shapes; | ||
+ | |||
+ | namespace ezFIT.Tools.Controls | ||
+ | { | ||
+ | /// | ||
+ | /// < | ||
+ | /// Interaction logic for ucUserNotification.xaml | ||
+ | /// </ | ||
+ | /// | ||
+ | public partial class ucUserNotification : UserControl | ||
+ | { | ||
+ | // | ||
+ | // Fields | ||
+ | // | ||
+ | private string _Message = ""; | ||
+ | private string _Title = ""; | ||
+ | |||
+ | // | ||
+ | // Properties | ||
+ | // | ||
+ | public string Message | ||
+ | { | ||
+ | get { return _Message; } | ||
+ | set { _Message = value;} | ||
+ | } | ||
+ | public string Title | ||
+ | { | ||
+ | get { return _Title; } | ||
+ | set { _Title = value; } | ||
+ | } | ||
+ | public bool IsNotificationAreaVisible { get; set; } | ||
+ | |||
+ | // | ||
+ | // RoutedEvent: | ||
+ | // | ||
+ | #region RoutedEvent: | ||
+ | public static readonly RoutedEvent OnUserNotificationRoutedEvent = EventManager.RegisterRoutedEvent( | ||
+ | " | ||
+ | | ||
+ | // | ||
+ | | ||
+ | | ||
+ | |||
+ | // Custom handler delegate (instead of RoutedEventHandler) | ||
+ | public delegate void UserNotificationRoutedEventHandler(object sender, UserNotificationRoutedEventArgs e); | ||
+ | |||
+ | // CLR accessor (property wrapper) for the routed event | ||
+ | //public event RoutedEventHandler OnUserNotification | ||
+ | //{ | ||
+ | // add { AddHandler(OnUserNotificationRoutedEvent, | ||
+ | // remove { RemoveHandler(OnUserNotificationRoutedEvent, | ||
+ | //} | ||
+ | |||
+ | // CLR accessor (property wrapper) for the custom routed event | ||
+ | public event UserNotificationRoutedEventHandler OnUserNotification | ||
+ | { | ||
+ | add { AddHandler(OnUserNotificationRoutedEvent, | ||
+ | remove { RemoveHandler(OnUserNotificationRoutedEvent, | ||
+ | } | ||
+ | |||
+ | // Method to raise event | ||
+ | //private void RaiseOnUserNotificationRoutedEvent() | ||
+ | //{ | ||
+ | // RoutedEventArgs newEventArgs = new RoutedEventArgs(ucEnvironmentManager.OnUserNotificationRoutedEvent); | ||
+ | // RaiseEvent(newEventArgs); | ||
+ | //} | ||
+ | private void RaiseOnUserNotificationRoutedEvent(string aMessage, string aTitle="", | ||
+ | { | ||
+ | UserNotificationRoutedEventArgs newEventArgs = new UserNotificationRoutedEventArgs(ucUserNotification.OnUserNotificationRoutedEvent, | ||
+ | RaiseEvent(newEventArgs); | ||
+ | } | ||
+ | #endregion | ||
+ | |||
+ | /// | ||
+ | /// < | ||
+ | /// Constructor | ||
+ | /// </ | ||
+ | /// | ||
+ | public ucUserNotification() | ||
+ | { | ||
+ | InitializeComponent(); | ||
+ | |||
+ | RefreshUserNotificationVisibility(); | ||
+ | } | ||
+ | |||
+ | /// | ||
+ | /// < | ||
+ | /// Refresh currently set visibility. | ||
+ | /// </ | ||
+ | /// | ||
+ | private void RefreshUserNotificationVisibility() | ||
+ | { | ||
+ | if (IsNotificationAreaVisible) | ||
+ | { | ||
+ | txtUserNotification.Visibility = Visibility.Visible; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | txtUserNotification.Visibility = Visibility.Collapsed; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /// | ||
+ | /// < | ||
+ | /// Send user notification (triggering event). | ||
+ | /// </ | ||
+ | /// <param name=" | ||
+ | /// | ||
+ | public void SendUserNotification(string aMessage, string aTitle, MessageBoxImage aMessageBoxImage=MessageBoxImage.None) | ||
+ | { | ||
+ | _Message = aMessage; | ||
+ | _Title = aTitle; | ||
+ | RaiseOnUserNotificationRoutedEvent(aMessage, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /// | ||
+ | /// UserNotificationEventArgs: | ||
+ | /// | ||
+ | public class UserNotificationRoutedEventArgs : RoutedEventArgs | ||
+ | { | ||
+ | private readonly string _Message; | ||
+ | private readonly string _Title; | ||
+ | private readonly MessageBoxImage _MessageBoxImage; | ||
+ | |||
+ | public string Message | ||
+ | { | ||
+ | get { return _Message; } | ||
+ | } | ||
+ | |||
+ | public string Title | ||
+ | { | ||
+ | get { return _Title; } | ||
+ | } | ||
+ | |||
+ | public MessageBoxImage MessageBoxImage | ||
+ | { | ||
+ | get { return _MessageBoxImage; | ||
+ | } | ||
+ | |||
+ | /// | ||
+ | /// < | ||
+ | /// Constructor | ||
+ | /// </ | ||
+ | /// <param name=" | ||
+ | /// <param name=" | ||
+ | /// <param name=" | ||
+ | /// | ||
+ | public UserNotificationRoutedEventArgs(RoutedEvent aRoutedEvent, | ||
+ | MessageBoxImage aMessageBoxImage=MessageBoxImage.None) : base(aRoutedEvent) | ||
+ | { | ||
+ | this._Message | ||
+ | this._Title | ||
+ | this._MessageBoxImage = aMessageBoxImage; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | UserControl to display user notification. | ||
+ | '' | ||
+ | <code xml> | ||
+ | < | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | < | ||
+ | <Border Name=" | ||
+ | Margin=" | ||
+ | HorizontalAlignment=" | ||
+ | BorderBrush=" | ||
+ | Background=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | < | ||
+ | Margin=" | ||
+ | HorizontalAlignment=" | ||
+ | BorderBrush=" | ||
+ | Background=" | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | <Button Name=" | ||
+ | <Path Data=" | ||
+ | Stretch=" | ||
+ | HorizontalAlignment=" | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | <code csharp> | ||
+ | using System; | ||
+ | using System.Collections.Generic; | ||
+ | using System.Linq; | ||
+ | using System.Text; | ||
+ | using System.Windows; | ||
+ | using System.Windows.Controls; | ||
+ | using System.Windows.Data; | ||
+ | using System.Windows.Documents; | ||
+ | using System.Windows.Input; | ||
+ | using System.Windows.Media; | ||
+ | using System.Windows.Media.Imaging; | ||
+ | using System.Windows.Navigation; | ||
+ | using System.Windows.Shapes; | ||
+ | using System.Windows.Threading; | ||
+ | |||
+ | namespace ezFIT.Tools.Controls | ||
+ | { | ||
+ | /// < | ||
+ | /// Interaction logic for ucUserNotificationArea.xaml | ||
+ | /// </ | ||
+ | public partial class ucUserNotificationArea : UserControl | ||
+ | { | ||
+ | // | ||
+ | // Fields | ||
+ | // | ||
+ | private string _Message | ||
+ | private string _Title = ""; | ||
+ | private double _MessageTimeSpanInSeconds = 10.0; | ||
+ | private MessageBoxImage _MessageBoxImage = MessageBoxImage.None; | ||
+ | DispatcherTimer _Timer = new DispatcherTimer(); | ||
+ | |||
+ | // | ||
+ | // Properties | ||
+ | // | ||
+ | public string Text | ||
+ | { | ||
+ | get { return _Message; } | ||
+ | set { _Message = value; SetTextMessage(_Message); | ||
+ | } | ||
+ | |||
+ | public string Message | ||
+ | { | ||
+ | get { return _Message; } | ||
+ | set { _Message = value; SetTextMessage(_Message); | ||
+ | } | ||
+ | |||
+ | public string Title | ||
+ | { | ||
+ | get { return _Title; } | ||
+ | set { _Title = value; } | ||
+ | } | ||
+ | |||
+ | public double MessageTimeSpanInSeconds | ||
+ | { | ||
+ | get { return _MessageTimeSpanInSeconds; | ||
+ | set { _MessageTimeSpanInSeconds = value; } | ||
+ | } | ||
+ | |||
+ | public MessageBoxImage MessageBoxImage | ||
+ | { | ||
+ | get { return _MessageBoxImage; | ||
+ | set { _MessageBoxImage = value; } | ||
+ | } | ||
+ | |||
+ | /// | ||
+ | /// < | ||
+ | /// Constructor | ||
+ | /// </ | ||
+ | /// | ||
+ | public ucUserNotificationArea() | ||
+ | { | ||
+ | InitializeComponent(); | ||
+ | } | ||
+ | |||
+ | /// | ||
+ | /// < | ||
+ | /// Set text message to the specified time span. | ||
+ | /// Time span is specified in seconds (default is 10 secs). | ||
+ | /// </ | ||
+ | /// <param name=" | ||
+ | /// <param name=" | ||
+ | /// | ||
+ | public void SetTextMessage(string aMessage, string aTitle="", | ||
+ | MessageBoxImage aMessageBoxImage=MessageBoxImage.None) | ||
+ | { | ||
+ | txtMessage.Text | ||
+ | txtTitle.Text | ||
+ | MessageTimeSpanInSeconds = aTimeSpanInSeconds; | ||
+ | MessageBoxImage | ||
+ | |||
+ | // Title visibility | ||
+ | if (aTitle.Trim() == string.Empty) | ||
+ | { | ||
+ | txtMessage.Visibility = Visibility.Collapsed; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | txtMessage.Visibility = Visibility.Visible; | ||
+ | } | ||
+ | |||
+ | SetBorderColor(); | ||
+ | |||
+ | // Make control visible for specified time (or permanent if time is 0.0) | ||
+ | this.Visibility = Visibility.Visible; | ||
+ | if (aTimeSpanInSeconds > 0.0) | ||
+ | { | ||
+ | ActivateTimer(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /// | ||
+ | /// < | ||
+ | /// Set border color depending on specified messagebox image. | ||
+ | /// </ | ||
+ | /// | ||
+ | private void SetBorderColor() | ||
+ | { | ||
+ | // Border visibility | ||
+ | switch (MessageBoxImage) | ||
+ | { | ||
+ | case System.Windows.MessageBoxImage.Question: | ||
+ | case System.Windows.MessageBoxImage.Warning: | ||
+ | brdUserNotificationArea.BorderBrush = Brushes.Yellow; | ||
+ | break; | ||
+ | |||
+ | case System.Windows.MessageBoxImage.Error: | ||
+ | brdUserNotificationArea.BorderBrush = Brushes.Crimson; | ||
+ | break; | ||
+ | |||
+ | default: | ||
+ | case System.Windows.MessageBoxImage.Information: | ||
+ | case System.Windows.MessageBoxImage.None: | ||
+ | brdUserNotificationArea.BorderBrush = Brushes.LightGray; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | /// | ||
+ | /// < | ||
+ | /// Activate timer to display notification message. | ||
+ | /// </ | ||
+ | /// | ||
+ | private void ActivateTimer() | ||
+ | { | ||
+ | // using System.Windows.Threading; | ||
+ | // | ||
+ | _Timer.Interval = TimeSpan.FromSeconds(_MessageTimeSpanInSeconds); | ||
+ | _Timer.Tick += new EventHandler(timer_Tick); | ||
+ | _Timer.Start(); | ||
+ | } | ||
+ | |||
+ | /// | ||
+ | /// < | ||
+ | /// Tick event handler for Timer. | ||
+ | /// </ | ||
+ | /// <param name=" | ||
+ | /// <param name=" | ||
+ | /// | ||
+ | void timer_Tick(object sender, EventArgs e) | ||
+ | { | ||
+ | // Do something every tick | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | |||
+ | HideNotification(); | ||
+ | } | ||
+ | |||
+ | private void btnClose_Click(object sender, RoutedEventArgs e) | ||
+ | { | ||
+ | HideNotification(); | ||
+ | } | ||
+ | |||
+ | private void HideNotification() | ||
+ | { | ||
+ | // | ||
+ | _Timer.Stop(); | ||
+ | this.Visibility = Visibility.Collapsed; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | UserControl placed in control that triggers a message: | ||
+ | <code xml> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | UserControl placed in parent control of the control that triggers a message. | ||
+ | <code xml> | ||
+ | <!--User Notification Area--> | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | Method to display message: | ||
+ | <code csharp> | ||
+ | /// | ||
+ | /// < | ||
+ | /// Loaded event handler for user control. | ||
+ | /// </ | ||
+ | /// <param name=" | ||
+ | /// <param name=" | ||
+ | /// | ||
+ | private void UserControl_Loaded(object sender, RoutedEventArgs e) | ||
+ | { | ||
+ | . . . | ||
+ | |||
+ | // Subscribe to Events | ||
+ | AddHandler(ucUserNotification.OnUserNotificationRoutedEvent, | ||
+ | } | ||
+ | |||
+ | /// | ||
+ | /// < | ||
+ | /// Set user notification in the display area. | ||
+ | /// </ | ||
+ | /// <param name=" | ||
+ | /// <param name=" | ||
+ | /// | ||
+ | private void UserNotification(object source, UserNotificationRoutedEventArgs args) | ||
+ | { | ||
+ | // Display message for 4 sec | ||
+ | ctrlUserNotificationArea.SetTextMessage(args.Message, | ||
+ | } | ||
+ | </ | ||
== Resources == | == Resources == | ||
* [[http:// | * [[http:// | ||
* [[http:// | * [[http:// |