Introduction
I want to demonstrate how you can design loosely coupled events between user-controls and their parent or between user-controls themselves.
Background
A good design pattern should cater for loosely coupled controls within an application, a parent shouldn't need to know about what user controls it
has within the project, only that the parent has the delegated events awaiting calls from child controls to act upon them - be the user control added to the application or not.
Project structure
Below is the structure of the Visual Studio 2010 application:
Fig 1
In the project I have a MainWindow
class that will host the two user control objects. There is an argument class (carArgs
) that will be used
to communicate data between the user controls and the parent and vice versa. There is also an
XML file just to bind some data to the grids.
The idea of the application is to have two controls within the parent. The parent has a grid (so do the user controls). When I click on a row within
the parent grid and select which control I wish to send the data to (which will select that row too, in that user control), and vice versa, the control
can make the parent control select the row that is in the child control. The parent doesn't need to know anything about the child, only have the delegated
event available to pick-up the call from the child and act upon it.
The code explained
Main Class (XAML)
The important piece of code when adding the user control is the event binding. In the code below,
the user control has a public event called NotifyedUserControl
that the parent binds to its method called ctrl_NotifyedUserControl
so when the child user control calls the method event within
its own class, this will find its way back to the parent method ctrl_NotifyedUserControl
along with any parameters that were declared within the signatures.
<UserControls:HrCars Grid.Row="0" Grid.Column="0"
x:Name="ctrlLoadHr" Margin="5"
IsEnabled="true" VerticalAlignment="Center"
HorizontalAlignment="Center" NotifyedUserControl="ctrl_NotifyedUserControl"></UserControls:HrCars>
The Main class (C#)
Below you can see the private method ctrl_NotifyedUserControl
that
is bound to the child control NotifyedUserControl
event.
It will then call the public methods with the other control or a method within the main class to select the appropriate row within the grid.
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 UserControlEventing.Models;
namespace UserControlEventing
{
public partial class MainWindow : Window
{
#region Class Variable
public CarArgs ParamEventArg { get; set; }
#endregion
public MainWindow()
{
InitializeComponent();
}
#region Delegate Event Binding
private void ctrl_NotifyedUserControl(object sender, Models.CarArgs arg)
{
switch (arg.ControlDestination.ToString())
{
case "Hr":
this.ctrlLoadHr.SetUserControl(arg);
break;
case "Sales":
this.ctrlLoadSales.SetUserControl(arg);
break;
case "Main":
this.mainDataGrid.SelectedIndex= arg.SelectedDatagridRowIndex;
break;
}
}
#endregion
#region Button Event
private void btnCallControls_Click(object sender, RoutedEventArgs e)
{
ParamEventArg = new CarArgs();
ParamEventArg.SelectedDatagridRowIndex = mainDataGrid.SelectedIndex;
ParamEventArg.ControlDestination = (ControlType)Enum.Parse(typeof(ControlType),
((ComboBoxItem)this.cboUserControls.SelectedItem).Tag.ToString(), true);
switch (this.cboUserControls.SelectionBoxItem.ToString())
{
case "Hr UserControl":
this.ctrlLoadHr.SetUserControl(ParamEventArg);
break;
case "Sales UserControl":
this.ctrlLoadSales.SetUserControl(ParamEventArg);
break;
case "Both UserControls":
this.ctrlLoadHr.SetUserControl(ParamEventArg);
this.ctrlLoadSales.SetUserControl(ParamEventArg);
break;
}
}
#endregion
}
}
Control code (C#)
Notice the declaration of the delegate - NotifyUserControl
, its signature and the event - NotifyedUserControl
.
The carArgs
class is also passed back to the parent or another user control.
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 UserControlEventing.Models;
namespace UserControlEventing.UserControls
{
public partial class HrCars : UserControl
{
public delegate void NotifyUserControl(object sender, CarArgs arg);
public event NotifyUserControl NotifyedUserControl;
public CarArgs ParamEventArg { get; set; }
public HrCars()
{
InitializeComponent();
}
public void SetUserControl(CarArgs arg)
{
this.dataGrid.SelectedIndex = arg.SelectedDatagridRowIndex;
}
private void btnCallControls_Click(object sender, RoutedEventArgs e)
{
ParamEventArg = new CarArgs();
ParamEventArg.SelectedDatagridRowIndex = this.dataGrid.SelectedIndex;
ParamEventArg.ControlDestination = (ControlType)Enum.Parse(typeof(ControlType),
((ComboBoxItem)this.cboUserControls.SelectedItem).Tag.ToString(), true);
this.NotifyedUserControl(this, ParamEventArg);
}
}
}
Argument class (C#)
namespace UserControlEventing.Models
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
public class CarArgs
{
public int SelectedDatagridRowIndex { get; set; }
public ControlType ControlDestination { get; set; }
}
public enum ControlType
{
Hr,
Sales,
Main,
Hr_Sales
}
}
The application running
Below you can see the application running, with the two user controls and the parent. If you select a row in the parent and select
a user control from the dropdown and click Push to control, you can see that the other control selects the same row as the calling event (fig 3).
Fig 2
Fig 3
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.