Loader Custom Control: Dynamically Loading User Controls in Silverlight 2
I create a lot of demo applications, and with Silverlight 2 that means creating a lot of user controls. Sometimes I build entire applications and other times I build simple and focused user controls. Sometimes I have a dozen user controls that I use to demonstrate different topics at events. I created a simple custom user control that loads another user control on demand. This has been very helpful for presentations and for using samples for my Silverlight 2 book.
The custom control I created is called MenuView. It shows a ListBox on the left that displays the information about each user control that I want to load. When the user selects the ListBox item, the user control is loaded dynamically on the right.
Its pretty straightforward in appearance and can certainly be spruced up. The purpose is to allow me an easy way to dynamically load control I want to demonstrate. The basic structure of the MenuView control is a Grid (shown below). The left hand side holds the ListBox and the right hand side contains a StackPanel, which is where the user controls will be loaded dynamically.
<Grid x:Name="LayoutRoot" Background="#FF2D2D2D">
<Grid.RowDefinitions>
<RowDefinition Height="46"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="215"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Samples" Margin="10,10,10,10"
Foreground="#FFFFFFFF" Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Center"/>
<ListBox Margin="10,10,10,20" x:Name="lstMenu"
ItemTemplate="{StaticResource MenuItemDataTemplate}"
ItemsSource="{Binding Mode=OneWay}" Grid.Row="1"
Grid.Column="0" Style="{StaticResource ListBoxStyle}" />
<StackPanel HorizontalAlignment="Stretch" Margin="10,10,10,10"
VerticalAlignment="Stretch" Grid.Column="1"
x:Name="ContentPanel" Grid.RowSpan="2"/>
</Grid>
The MenuView loads controls when the ListBox selection changes. It creates an instance of the user control using its type, and its the control to the StackPanel (shown below).
private void lstMenu_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedMenuItem = lstMenu.SelectedItem as MenuItem;
UIElement newUIElement = Activator.CreateInstance(selectedMenuItem.ControlType) as UIElement;
ShowControl(newUIElement);
}
private void ShowControl(UIElement newUIElement)
{
while (ContentPanel.Children.Count > 0)
ContentPanel.Children.RemoveAt(0);
ContentPanel.Children.Add(newUIElement);
}
All of this in encapsulate din a Silverlight class library. This allows me to refer to this control in several applications simply by referencing the DLL. So in a Silverlight 2 application where I have several unrelated user controls that I want to use in a presentation, I create a list of MenuItem classes and pass them to the MenuView control. The MenuItem class is a simple class with Title, Description and ControlType properties. Title and Description are displayed in the ListBox menu. The ControlType is used to dynamically load the user control when the selection is made.
private void Application_Startup(object sender, StartupEventArgs e)
{
ObservableCollection<MenuItem> menu = new ObservableCollection<MenuItem>
{
new MenuItem {
Title = "Simple Binding", ControlType = typeof(BindingSimple),
Description = "Shows basic binding to the DataContext"
},
new MenuItem {
Title = "Blend Binding", ControlType = typeof(BlendBinding),
Description = "Shows basic binding to the DataContext created through Expression Blend"
},
new MenuItem {
Title = "Manual Push/Pull", ControlType = typeof(BoundManually),
Description = "Shows pushing and pulling data without using binding"
},
new MenuItem {
Title = "DataContext Binding", ControlType = typeof(DataContextBinding),
Description = "Shows binding using the DataContext at different UIElement levels"
},
new MenuItem {
Title = "RunTime Binding", ControlType = typeof(RuntimeBinding),
Description = "Shows how to bind in .NET code"
}
};
this.RootVisual = new MenuView(menu);
}
If interested, the source code for this control can be downloaded here.