Events (Direct)

Events help user controls communicate with parent controls.

A user control would create an event delegate:

public delegate void OnMyEventHandler(object sender, EventArgs e);
public event OnMyEventHandler OnMyEvent;

When the user control needs to trigger the event, call the event handler:

if (OnMyEvent != null)
{
  OnMyEvent(this, new EventArgs());
}  

Or create a function to handle it:

protected void MyEventEvent()
{
    OnMyEventHandler handler = OnMyEvent;
    if (handler != null)
    {
        handler(this, new EventArgs());
    }
}

The parent control implements an event handler to respond to that event:

public MyClassConstructor()
{
  usercontrol myUserControl = new usercontrol();
  myUserControl.OnMyEvent += new userControl.OnMyEventHandler(catchevent);
}
 
...
void catchevent(object sender, EventArgs e)
{
     // Do some work to handle event
     Panel2.Controls.remove(((control)sender));
     //or Panel2.Controls.Clear();
}

Source: Diamonddrake, Daniweb.com

Example

A class would create an event delegate:

public class TParamData
{
  // Events
  public delegate void OnChangedHandler(object sender, EventArgs e);
  public event OnChangedHandler OnChanged;
  ...
  // Fields
  ...
  // Methods
  ...
}  

When the object instance needs to trigger the event, call the event handler:

public class TParamData
{
  // Events
  ...
  // Fields and Properties
  private int m_Data;
  public int Data
  {
     set 
     {
         m_Data = value;
         if (OnChange != null)
         {
           OnChanged(this, new EventArgs());  // trigger OnChanged event
         }
     }
   }
   ...  

The parent class implements an event handler to respond to that event:

public class MyClass
{
   // Fields
   private TParamData myParam;
 
   // Constructor
   public MyClass()
   {
     myParam = new TParamData();
     myParam.OnChanged += new TParamData.OnChangedHandler(Param_OnChanged);
   }
 
   // Event Handler 
   void Param_OnChanged(object sender, EventArgs e)
   {
     // Do some work if Param is changed
     this.WriteToInstrument(myParam);
   }
   ...
}   
PropertyChanged Event

To provide INotifyPropertyChanged support for classes implementing that interface, you need to provide the PropertyChanged event.

Example

using System.Collections.ObjectModel;  // For INotifyPropertyChanged
...
 
//========================================================================
// Class TMyClass
//========================================================================
public class TPerson : INotifyPropertyChanged
{
  // Declare events
  public event PropertyChangedEventHandler PropertyChanged;
 
  // Fields
  private string m_Name = "";
  private int    m_Age  = 0;
 
  // Properties
  public string Name
  { 
    get{ return m_Name; }
    set{ m_Name = value; OnPropertyChanged("Name"); }
  }
  public string Age
  { 
    get{ return m_Age; }
    set{ m_Age = value; OnPropertyChanged("Age"); }
  }
 
  // Constructor
  public TMyClass()
  {
  }
 
  // Handler
  protected void OnPropertyChanged(string PropertyName)
  {
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(PropertyName));
    }
  }
  ...
}  
Routed Events

In WPF, you also have access to Routed Events, which have additional advantages. Events can “tunnel down” or “bubble up” to other components in the visual tree.

RoutedEvents are particularly useful if the listener doesn't have a direct reference to the source of the event. For example you have a container control which must react to a specific event, but the container will not always know exactly which controls inside it can/will throw it. The controls can be several levels deep, or created by a template. – Source: Bubblewrap@Stackoverflow.com

Example

An example where a container handles an event from a control that it does not know about: (Source: http://soumya.wordpress.com/2009/12/31/wpf-simplified-part-7-routed-events)

Writing a custom routed event is similar to writing a dependency property,

public static readonly RoutedEvent OnMyActionEvent = EventManager.RegisterRoutedEvent(
                               "OnMyAction",               // Name of the custom routed event
                               RoutingStrategy.Bubble,     // The routing strategy
                               typeof(RoutedEventHandler), // Type of the event handler
                               typeof(MyControl));         // The type of the owner of this routed event 
 
// Provide CLR property wrapper for the routed event
public event RoutedEventHandler OnMyAction
{
    add { AddHandler(OnMyActionEvent , value); }
    remove { RemoveHandler(OnMyActionEvent , value); }
}
 
// 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), elements can handle events that are declared in a different element.

Attached Event using XAML:

<Grid Button.Click="ButtonClickHandler">
    <Button Height="100" Width="100" Content="Some Text"/>
</Grid>

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 Event programmatically:

<Grid x:Name="MyGrid">
    <Button Height="100" Width="100" Content="Some Text"/>
</Grid>
// In code...
this.MyGrid.AddHandler(Button.ClickEvent, new RoutedEventHandler(ButtonClickHandler));

Handler definition:

private void ButtonClickHandler(object sender, RoutedEventArgs e)
{
    // do something
    . . .
    e.Handled = true;  // mark event as handled so other listeners do try to handle it as well
}

Example

ucPopup.xaml:

<UserControl x:Class="InterUsrCtrlComm.ucPopupMnu"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="200">
    <Grid>
        <ToggleButton IsChecked="{Binding ElementName=popopmnuColorSelection, Path=IsOpen}" 
                      Content="Open Popup Menu" 
                      Width="130" Height="50" />
        <Popup Name="popopmnuColorSelection" 
               Visibility="Visible" Width="150"
               Placement="Bottom" 
               AllowsTransparency="False" 
               PopupAnimation="Fade" 
               VerticalOffset="-100" HorizontalOffset="100">
            <StackPanel>
                <TextBlock Background="Transparent" Foreground="White" FontWeight="Bold">Select one (double click):</TextBlock>
                <ListBox Name="lstColors" MouseDoubleClick="lstColors_MouseDoubleClick">
                    <ListBoxItem>Red</ListBoxItem>
                    <ListBoxItem>Green</ListBoxItem>
                    <ListBoxItem>Blue</ListBoxItem>
                </ListBox>
            </StackPanel>
        </Popup>
    </Grid>
</UserControl>

ucPopup.xaml.cs:

public partial class ucPopupMnu : UserControl
{
    // Register the routed event
    public static readonly RoutedEvent MenuItemSelectedEvent =
        EventManager.RegisterRoutedEvent("MenuItemSelected", RoutingStrategy.Bubble,
        typeof(RoutedEventHandler), typeof(ucPopupMnu));
 
    // CLR accessor (.NET wrapper) for routed event
    public event RoutedEventHandler MenuItemSelected
    {
        add { AddHandler(MenuItemSelectedEvent, value); }
        remove { RemoveHandler(MenuItemSelectedEvent, value); }
    }
 
    public ListBoxItem SelectedItem
    { 
        get { return (ListBoxItem)lstColors.SelectedItem; }
        set { lstColors.SelectedItem = value; }
    }
 
    public ucPopupMnu()
    {
        InitializeComponent();
    }
 
    private void lstColors_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        ListBoxItem selection = (ListBoxItem)lstColors.SelectedItem;
        //txtSelectedColor.Text = selection.Content.ToString();
 
        // Raise the routed event "selected"
        RaiseEvent(new RoutedEventArgs(ucPopupMnu.MenuItemSelectedEvent));
    }
}

And to handle events elsewhere:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
 
        // Attach menu event handler
        //popupmnu1.MenuItemSelected += new RoutedEventHandler(ucPopupMnu_MenuItemSelected);
        // or
        AddHandler(ucPopupMnu.MenuItemSelectedEvent, new RoutedEventHandler(ucPopupMnu_MenuItemSelected));
    }
 
    /// <summary>
    /// Event handler for Menu Item Selection in Popup menu.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ucPopupMnu_MenuItemSelected(object sender, RoutedEventArgs e)
    {
        // Take action based on the menu selection
        ListBoxItem selection = popupmnu1.SelectedItem;  // Get menu selection
        MessageDlg.Show( selection.Content.ToString() ); // Display it
    }
}

Another example using a Button (Source: http://msdn.microsoft.com/en-us/library/ms752288.aspx):

<Window  
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:SDKSample;assembly=SDKSampleLibrary"
    x:Class="SDKSample.RoutedEventCustomApp">
    <Window.Resources>
      <Style TargetType="{x:Type custom:MyButtonSimple}">
        <Setter Property="Height" Value="20"/>
        <Setter Property="Width" Value="250"/>
        <Setter Property="HorizontalAlignment" Value="Left"/>
        <Setter Property="Background" Value="#808080"/>
      </Style>
    </Window.Resources>
    <StackPanel Background="LightGray">
	    <custom:MyButtonSimple Name="mybtnsimple" Tap="TapHandler">Click to see Tap custom event work</custom:MyButtonSimple>
    </StackPanel>
</Window>
public class MyButtonSimple: Button
{
    // Create a custom routed event by first registering a RoutedEventID
    // This event uses the bubbling routing strategy
    public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
        "Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple));
 
    // Provide CLR accessors for the event
    public event RoutedEventHandler Tap
    {
            add { AddHandler(TapEvent, value); } 
            remove { RemoveHandler(TapEvent, value); }
    }
 
    // This method raises the Tap event
    void RaiseTapEvent()
    {
            RoutedEventArgs newEventArgs = new RoutedEventArgs(MyButtonSimple.TapEvent);
            RaiseEvent(newEventArgs);
    }
    // For demonstration purposes we raise the event when the MyButtonSimple is clicked
    protected override void OnClick()
    {
        RaiseTapEvent();
    }
}

Example of Custom RoutedEvent

UserNotification logic is composed of a ucUserNotification component that triggers the event, and a ucUserNotificationArea component to handle and display the event. This last component is usually placed in any parent control that needs to respond to user notifications triggered in child controls. There are no direct event subscriptions other than the AddHandle() performed on the parent control. It portrays how notifications can be triggers in any child controls, and then handled as an event at some ancestor control without having to know anything about the child control that triggered the event. This mechanism only works for VisualTree components. The alternative is to use CLR events, but then there must be direct subscriptions to events from the parent to the child control in order to handle those events, something we are avoiding here with this mechanism.

UserControl for UserNotification event trigger. ucUserNotification.xaml:

<UserControl x:Class="ezFIT.Tools.Controls.ucUserNotification"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="30" d:DesignWidth="300">
    <Grid>
        <TextBlock Name="txtUserNotification" Text="Notification" VerticalAlignment="Center" HorizontalAlignment="Center"/>
    </Grid>
</UserControl>

ucUserNotification.xaml.cs:

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
{
    ///============================================================================================
    /// <summary>
    /// Interaction logic for ucUserNotification.xaml
    /// </summary>
    ///============================================================================================
    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: OnUserNotification
        //-----------------------------------
        #region RoutedEvent: OnUserNotification
        public static readonly RoutedEvent OnUserNotificationRoutedEvent = EventManager.RegisterRoutedEvent(
                               "OnUserNotificationRoutedEvent",             // Name of the custom routed event
                               RoutingStrategy.Bubble,                      // The routing strategy
                               //typeof(RoutedEventHandler),                // Type of the event handler
                               typeof(UserNotificationRoutedEventHandler),  // Type of the event handler
                               typeof(ucUserNotification));                 // The type of the owner of this routed event 
 
         // 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, value); }
        //    remove { RemoveHandler(OnUserNotificationRoutedEvent, value); }
        //}
 
        // CLR accessor (property wrapper) for the custom routed event
        public event UserNotificationRoutedEventHandler OnUserNotification
        {
            add { AddHandler(OnUserNotificationRoutedEvent, value); }
            remove { RemoveHandler(OnUserNotificationRoutedEvent, value); }
        }
 
        // Method to raise event
        //private void RaiseOnUserNotificationRoutedEvent()
        //{
        //    RoutedEventArgs newEventArgs = new RoutedEventArgs(ucEnvironmentManager.OnUserNotificationRoutedEvent);
        //    RaiseEvent(newEventArgs);
        //}
        private void RaiseOnUserNotificationRoutedEvent(string aMessage, string aTitle="", MessageBoxImage aMessageBoxImage=MessageBoxImage.None)
        {
            UserNotificationRoutedEventArgs newEventArgs = new UserNotificationRoutedEventArgs(ucUserNotification.OnUserNotificationRoutedEvent, aMessage, aTitle, aMessageBoxImage);
            RaiseEvent(newEventArgs);
        }
        #endregion
 
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Constructor
        /// </summary>
        ///----------------------------------------------------------------------------------------
        public ucUserNotification()
        {
            InitializeComponent();
 
            RefreshUserNotificationVisibility();
        }
 
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Refresh currently set visibility.
        /// </summary>
        ///----------------------------------------------------------------------------------------
        private void RefreshUserNotificationVisibility()
        {
            if (IsNotificationAreaVisible)
            {
                txtUserNotification.Visibility = Visibility.Visible;
            }
            else
            {
                txtUserNotification.Visibility = Visibility.Collapsed;
            }
        }
 
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Send user notification (triggering event).
        /// </summary>
        /// <param name="aMessage"></param>
        ///----------------------------------------------------------------------------------------
        public void SendUserNotification(string aMessage, string aTitle, MessageBoxImage aMessageBoxImage=MessageBoxImage.None)
        {
            _Message = aMessage;
            _Title = aTitle;
            RaiseOnUserNotificationRoutedEvent(aMessage, aTitle, aMessageBoxImage);
        }
    }
 
    ///============================================================================================
    /// UserNotificationEventArgs: a custom event inherited from EventArgs.
    ///============================================================================================
    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; }
        } 
 
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="aRoutedEvent"></param>
        /// <param name="aMessage"></param>
        /// <param name="aTitle"></param>
        ///----------------------------------------------------------------------------------------
        public UserNotificationRoutedEventArgs(RoutedEvent aRoutedEvent, string aMessage, string aTitle="", 
            MessageBoxImage aMessageBoxImage=MessageBoxImage.None) : base(aRoutedEvent)
        {
            this._Message         = aMessage;
            this._Title           = aTitle;
            this._MessageBoxImage = aMessageBoxImage;
        }
    }
}

UserControl to display user notification. ucUserNotificationArea.xaml:

<UserControl x:Class="ezFIT.Tools.Controls.ucUserNotificationArea"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="75" d:DesignWidth="300">
    <Grid>
        <Border Name="brdUserNotificationArea" 
                Margin="5"
                HorizontalAlignment="Center" VerticalAlignment="Top"
                BorderBrush="LightGray" BorderThickness="2" CornerRadius="5"
                Background="LightGray" Canvas.ZIndex="99">
            <Border.Effect>
                <DropShadowEffect Opacity="0.5" ShadowDepth="5" BlurRadius="5" />
            </Border.Effect>
            <Border  
                Margin="5"
                HorizontalAlignment="Center" VerticalAlignment="Top"
                BorderBrush="White" BorderThickness="2" CornerRadius="5"
                Background="White" Canvas.ZIndex="99">
                <StackPanel>
                    <Grid>
                        <TextBlock Name="txtTitle" Text="Notification" FontWeight="Bold" Margin="5,5,15,0" VerticalAlignment="Center" Foreground="Black" />
                        <Button Name="btnClose" Width="10" Height="10" Margin="5,-10,0,0" HorizontalAlignment="Right" Style="{StaticResource IconButtonStyle}" Click="btnClose_Click">
                            <Path Data="{StaticResource CloseX}" Width="8" Height="8"
                                  Stretch="Fill" Stroke="DarkGray" StrokeThickness="2" Margin="0" 
                                  HorizontalAlignment="Right" VerticalAlignment="Top" />
                        </Button>
                    </Grid>
                    <TextBlock Name="txtMessage" Text="No news is good news!" Margin="5,0,5,5" VerticalAlignment="Center"/>
                </StackPanel>
            </Border>
        </Border>
    </Grid>
</UserControl>

ucUserNotificationArea.xaml.cs:

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;  // DispatcherTimer
 
namespace ezFIT.Tools.Controls
{
    /// <summary>
    /// Interaction logic for ucUserNotificationArea.xaml
    /// </summary>
    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; }
        }
 
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Constructor
        /// </summary>
        ///----------------------------------------------------------------------------------------
        public ucUserNotificationArea()
        {
            InitializeComponent();
        }
 
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Set text message to the specified time span. 
        /// Time span is specified in seconds (default is 10 secs).  Set to 0.0 if permanent display is desired.
        /// </summary>
        /// <param name="aMessage"></param>
        /// <param name="aTimeSpanInSeconds">Time span in seconds (default is 10 secs)</param>
        ///----------------------------------------------------------------------------------------
        public void SetTextMessage(string aMessage, string aTitle="", double aTimeSpanInSeconds = 10.0, 
            MessageBoxImage aMessageBoxImage=MessageBoxImage.None)
        {
            txtMessage.Text          = aMessage;
            txtTitle.Text            = aTitle;
            MessageTimeSpanInSeconds = aTimeSpanInSeconds;
            MessageBoxImage          = aMessageBoxImage;
 
            // 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();
            }
        }
 
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Set border color depending on specified messagebox image.
        /// </summary>
        ///----------------------------------------------------------------------------------------
        private void SetBorderColor()
        {
            // Border visibility
            switch (MessageBoxImage)
            {
                case System.Windows.MessageBoxImage.Question:
                case System.Windows.MessageBoxImage.Warning:  //case System.Windows.MessageBoxImage.Exclamation:
                    brdUserNotificationArea.BorderBrush = Brushes.Yellow;
                    break;
 
                case System.Windows.MessageBoxImage.Error:  //case System.Windows.MessageBoxImage.Stop: //case System.Windows.MessageBoxImage.Hand:
                    brdUserNotificationArea.BorderBrush = Brushes.Crimson;
                    break;
 
                default:
                case System.Windows.MessageBoxImage.Information: //case System.Windows.MessageBoxImage.Asterisk:
                case System.Windows.MessageBoxImage.None:
                    brdUserNotificationArea.BorderBrush = Brushes.LightGray;  // Brushes.LimeGreen;
                    break;
            }
        }
 
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Activate timer to display notification message.
        /// </summary>
        ///----------------------------------------------------------------------------------------
        private void ActivateTimer()
        {
          // using System.Windows.Threading;
          //DispatcherTimer timer = new DispatcherTimer();
          _Timer.Interval = TimeSpan.FromSeconds(_MessageTimeSpanInSeconds); // Default: 10 seconds
          _Timer.Tick += new EventHandler(timer_Tick);       // Subscribe to Tick event handler
          _Timer.Start();
        }
 
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Tick event handler for Timer.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///----------------------------------------------------------------------------------------
        void timer_Tick(object sender, EventArgs e)
        {
            // Do something every tick
            //((DispatcherTimer)sender).Stop();        // stop timer
            //_Timer.Stop();        // stop timer
            //this.Visibility = Visibility.Collapsed;    // hide this usercontrol
 
            HideNotification();
        }
 
        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            HideNotification();
        }
 
        private void HideNotification()
        {
            //((DispatcherTimer)sender).Stop();        // stop timer
            _Timer.Stop();        // stop timer
            this.Visibility = Visibility.Collapsed;    // hide this usercontrol
        }    
 
    }
}

UserControl placed in control that triggers a message:

<toolscontrols:ucUserNotification x:Name="msgUserNotification" IsNotificationAreaVisible="False"/>

UserControl placed in parent control of the control that triggers a message. This is where the notification will be displayed:

<!--User Notification Area-->
<toolscontrols:ucUserNotificationArea x:Name="ctrlUserNotificationArea" />

Method to display message:

///----------------------------------------------------------------------------------------
/// <summary>
/// Loaded event handler for user control.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
///----------------------------------------------------------------------------------------
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    . . .
 
    // Subscribe to Events
    AddHandler(ucUserNotification.OnUserNotificationRoutedEvent, new ucUserNotification.UserNotificationRoutedEventHandler(UserNotification));
}
 
///----------------------------------------------------------------------------------------
/// <summary>
/// Set user notification in the display area.
/// </summary>
/// <param name="source"></param>
/// <param name="args"></param>
///----------------------------------------------------------------------------------------
private void UserNotification(object source, UserNotificationRoutedEventArgs args)
{      
    // Display message for 4 sec
    ctrlUserNotificationArea.SetTextMessage(args.Message, args.Title, 4 /* secs */, args.MessageBoxImage);
}
Resources