Loading Child User Controls
One approach is to create a central page that acts as the main window for your application for its entire lifetime. However, this page can change itself by loading new user controls into its hierarchy of elements.
One example of this design is the menu page that's used for most of the sample projects that accompany this book. This page uses a Grid to divide itself into two main sections (separated by a horizontal grid splitter). At the top is a list of all the pages you can visit. When you select one of the times from this list, it's loaded into the larger content region underneath, as shown in Figure 3-18.
- Figure 3-18. A window that loads user controls dynamically
Dynamically loading a user control is easy—you simply need to create an instance of the appropriate class and then add it to a suitable container, such as a Border, ScrollViewer, StackPanel, or Grid.
The example shown previously uses the Border element, which is a content control that adds the ability to paint a border around its edges using the BorderBrush and BorderThick-ness properties. Here's the markup (without the list of items in the ListBox):
<UserControl x: Qass="Resources.MenuPage" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:basics=
"clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"> <Grid x:Name="LayoutRoot" Background="White" Margin="5"> <Grid.RowDefinitions> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="3*"></RowDefinition> </Grid.RowDefinitions>
<ListBox SelectionChanged="lstPages_SelectionChanged"> </ListBox>
<basics:GridSplitter Grid.Row="1" Margin="0 3" HorizontalAlignment="Stretch" Height="2"></basics:GridSplitter>
<Border Grid.Row="2" BorderBrush="SlateGray" BorderThickness="1" x:Name="borderPlaceholder" Background="AliceBlue"></Border> </Grid> </UserControl>
In this example, the Border is named borderPlaceholder. Here's how you might display a new custom user control named Page2 in the borderPlaceholder region:
Page2 newPage = new Page (); borderPlaceholder.Child = newPage;
If you're using a different container, you may need to set a different property instead. For example, Silverlight's layout panels can hold multiple controls, and so provide a Children collection. You need to clear this collection and then add the new control to it. Here's an example that duplicates the previous code, assuming you've replaced the Border with a single-celled Grid:
gridPlaceholder.Children.Clear();
gridPlaceholder.Children.Add(newPage);
If you create a Grid without declaring any rows or columns, the Grid will have a single proportionately sized cell that fits all the available space. Thus, adding a control to that Grid produces the same result as adding it to a Border.
The actual code that's used in the examples is a bit different, because it needs to work for all buttons. To determine which type of user control to create, the code examines the ListBox-Item that was just clicked. It then uses reflection to create the corresponding user control object:
private void lstPages_SelectionChanged(object sender, SelectionChangedEventArgs e) {
// Get the selected item.
string newPageName = ((ListBoxItei )e.AddedItems[0]).Content.ToString();
// Create an instance of the page named // by the current button. Type type = this.GetType(); Assembly assembly = type.Assembly;
UserControl newPage = (UserControl)assembly.CreateInstance( type.Namespace + "." + newPageName);
// Show the page. pagePlaceholder.Child = newPage;
The process of showing the newly created user control—that is, setting the Border.Child property—is exactly the same.
The technique shown here is quite common, but it's not suited for all scenarios. Its key drawback is that it slots new content into an existing layout. In the previous example, that means the ListBox always remains fixed at the top of the page. This is handy if you're trying to create a toolbar that always remains accessible, but not as convenient if you want to switch to an entirely different task.
An alternative approach is to change the entire page from one control to another. The basic technique is to use a simple layout container as your application's root visual. You can then load user controls into the root visual when required, and unload them after. (The root visual itself can never be replaced once the application has started.) This useful technique is described in Chapter 6.
Post a comment