== 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: [[http://www.daniweb.com/forums/thread234998.html|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: [[http://stackoverflow.com/questions/2536950/c-wpf-routedevent-in-wpf-class-that-isnt-a-uielement|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**: ''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 { /// /// 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). Set to 0.0 if permanent display is desired. /// /// /// Time span in seconds (default is 10 secs) ///---------------------------------------------------------------------------------------- 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(); } } ///---------------------------------------------------------------------------------------- /// /// 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: //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; } } ///---------------------------------------------------------------------------------------- /// /// Activate timer to display notification message. /// ///---------------------------------------------------------------------------------------- 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(); } ///---------------------------------------------------------------------------------------- /// /// Tick event handler for Timer. /// /// /// ///---------------------------------------------------------------------------------------- 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: UserControl placed in parent control of the control that triggers a message. This is where the notification will be displayed: Method to display message: ///---------------------------------------------------------------------------------------- /// /// Loaded event handler for user control. /// /// /// ///---------------------------------------------------------------------------------------- private void UserControl_Loaded(object sender, RoutedEventArgs e) { . . . // Subscribe to Events AddHandler(ucUserNotification.OnUserNotificationRoutedEvent, new ucUserNotification.UserNotificationRoutedEventHandler(UserNotification)); } ///---------------------------------------------------------------------------------------- /// /// Set user notification in the display area. /// /// /// ///---------------------------------------------------------------------------------------- private void UserNotification(object source, UserNotificationRoutedEventArgs args) { // Display message for 4 sec ctrlUserNotificationArea.SetTextMessage(args.Message, args.Title, 4 /* secs */, args.MessageBoxImage); } == Resources == * [[http://msdn.microsoft.com/en-us/library/system.eventargs.aspx|MSDN EventArgs Class]] * [[http://msdn.microsoft.com/en-us/library/ms752288.aspx|MSDN How to: Create a Custom Routed Event]]