User Controls and Intercommunication

For applications that are composed of multiple user controls, there needs to be coordination and communication between them. For example, an application's MainWindow.xaml:

<Window x:Class="InterUsrCtrlComm.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:InterUsrCtrlComm"
        Title="Inter User Control Communication" Height="350" Width="525">
    <Grid>
        <local:ucContent x:Name="content1"/>
        <local:ucPopupMnu x:Name="popupmnu1"/>
    </Grid>
</Window>

Attach menu event programmatically (in C#):

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 InterUsrCtrlComm
{
    /// <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);
        }
 
        /// <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)
        {
            // Get menu selection
            ListBoxItem selection = popupmnu1.SelectedItem;
 
            // Take action based on the menu selection
            content1.SelectedTabItem = selection.Content.ToString();
        }
   }
}

If the event is defined with XAML (MainWindows.xaml), then:

<Window x:Class="InterUsrCtrlComm.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:InterUsrCtrlComm"
        Title="Inter User Control Communication" Height="350" Width="525">
    <Grid>
        <local:ucContent x:Name="content1"/>
        <local:ucPopupMnu x:Name="popupmnu1" MenuItemSelected="ucPopupMnu_MenuItemSelected"/>
    </Grid>
</Window>

The code-behind looks like (MainWindows.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 InterUsrCtrlComm
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
 
            // This next line should not be present, since XAML will add it automatically in InitializeComponent()
            //popupmnu1.MenuItemSelected += 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)
        {
            // Get menu selection
            ListBoxItem selection = popupmnu1.SelectedItem;
 
            // Take action based on the menu selection
            content1.SelectedTabItem = selection.Content.ToString();
        }
    }
}

It contains 2 user controls:

  • ucContent which has the main content for the application.
  • ucPopupMnu which has a popup menu that triggers events that should affect the content in ucContent.

The MainWindow coordinates communication between these user controls. ucPopupMnu has routed events that are then intercepted by MainWindow, and from here trigger some action in ucContent.

This is how it looks: ucContent

ucContent.xaml

<UserControl x:Class="InterUsrCtrlComm.ucContent"
             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="600">
    <Grid>
        <TabControl Name="tcMain">
            <TabItem Name="tabRed" Header="Red">
                <Grid Background="Crimson"></Grid>
            </TabItem>
            <TabItem Name="tabGreen" Header="Green">
                <Grid Background="DarkGreen"></Grid>
            </TabItem>
            <TabItem Name="tabBlue" Header="Blue">
                <Grid Background="Navy"></Grid>
            </TabItem>
        </TabControl>
    </Grid>
</UserControl>

ucContent.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 InterUsrCtrlComm
{
    /// <summary>
    /// Interaction logic for ucContent.xaml
    /// </summary>
    public partial class ucContent : UserControl
    {
        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Get or set the Selected Tab Item by providing the tab label (string).
        /// </summary>
        //-----------------------------------------------------------------------------------------
        public string SelectedTabItem
        {
            get 
            {
                TabItem tab = (TabItem)tcMain.SelectedItem;
                return tab.Header.ToString(); 
            }
            set 
            { 
                 switch(value)
                 {
                     case "Red":
                         tcMain.SelectedItem = tabRed;
                         break;
                     case "Green":
                         tcMain.SelectedItem = tabGreen;
                         break;
                     case "Blue":
                         tcMain.SelectedItem = tabBlue;
                         break;
                 }
            }
        }
 
        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Constructor
        /// </summary>
        //-----------------------------------------------------------------------------------------
        public ucContent()
        {
            InitializeComponent();
        }
    }
}

ucPopupMnu.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>

ucPopupMnu.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 InterUsrCtrlComm
    {
        /// <summary>
        /// Interaction logic for ucPopupMnu.xaml
        /// </summary>
        public partial class ucPopupMnu : UserControl
        {
            // Register the routed event
            public static readonly RoutedEvent MenuItemSelectedEvent =
                EventManager.RegisterRoutedEvent("MenuItemSelected", RoutingStrategy.Bubble,
                typeof(RoutedEventHandler), typeof(ucPopupMnu));
 
            // .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));
            }
        }
    }
Resources