Now we're starting to dive into the world of Prism and modular development as well as a very standard, event driven, code-behind way of handling this project- meaning now we finally get to see some code!  To start things off, we'll look at the slightly more in-depth approach of beginning an application using Prism/MVVM and what it entails.  Also, to make one distinction early on, since I'm using the same database and WCF RIA Services to handle my data transfer, I've created the code-behind project within the same solution, so when I am in the Recruit project or any module, I'm working on the Prism/MVVM version, but when you see me in RecruitCB (clever shortening of Recruit Code-Behind), I'm using the code-behind version.

Setting up the Prism Project

The first thing I need to do is start a new Silverlight Application.  Once this is all setup, I have to do two things to start Prism-ifying the project- the Bootstrapper and Shell.  Bootstrapper is a class which will be used to initialize modules, load the shell, and take care of any initialization logic, whereas Shell is just the MainPage.xaml renamed.

Recruit Project Picture

Since we're using Prism, we also need references to the following assemblies:

Prism Assemblies picture

Since our shell is going to be all XAML, we'll look at the BootStrapper first.  When using Prism/Unity (the container for Prism, but you could also use CastleWindsor, Ninject, etc.), our BootStrapper implements UnityBootstrapper, the two most important methods from which, for our purposes, are CreateShell() and GetModuleCatalog().  CreateShell is going to create an instance of our shell using the Unity container and set that as the current RootVisual of our application.  GetModuleCatalog, on the other hand, is one of the ways we can gather and initialize our modules. With all those in place, the code for this basic bootstrapper setup looks like this:

public class Bootstrapper : UnityBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        Shell shell = Container.Resolve<Shell>();
        Application.Current.RootVisual = shell;
        return shell;
    }
    protected override IModuleCatalog GetModuleCatalog()
    {
        ModuleCatalog catalog = new ModuleCatalog();
        // add modules here
        return catalog;
    }
}

These, or at least the GetModuleCatalog, will get a little more robust as we move forward, but this handles our BootStrapper.cs for right now.  So what's next?  We'll step into the Shell.XAML.

Shell.XAML can be thought of as your main display that will hold regions (this term means something for Prism) to load modules into.  I know that I want a basic setup which has a title at the top, a status notification area in the upper right (to say 'Loading', etc.), a menu on the left, and the bulk of the window to be the main content region.  The resulting XAML looks something like this:

<Grid x:Name="LayoutRoot">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="48" />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Border Grid.ColumnSpan="2">
        <Border.Background>
            <LinearGradientBrush StartPoint=".5,0"
                                 EndPoint=".5,1">
                <GradientStopCollection>
                    <GradientStop Color="LightGray"
                                  Offset="0" />
                    <GradientStop Color="LightBlue"
                                  Offset=".9" />
                    <GradientStop Color="White"
                                  Offset="1" />
                </GradientStopCollection>
            </LinearGradientBrush>
        </Border.Background>
        <StackPanel Orientation="Horizontal"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Center"
                    Margin="24,0,0,0">
            <TextBlock Text="Telerik"
                       FontWeight="Bold"
                       FontSize="24" />
            <TextBlock Text="Recruiter"
                       FontSize="24" />
        </StackPanel>
    </Border>
    <!-- Notifications Region -->
    <ContentControl x:Name="NotificationRegion"
                    HorizontalAlignment="Right"
                    Grid.Column="1"
                    regions:RegionManager.RegionName="NotificationRegion" />
    <!-- Menu Region -->
    <ContentControl x:Name="MenuRegion"
                    Grid.Row="1"
                    regions:RegionManager.RegionName="MenuRegion" />
    <!-- Main Content Region -->
    <ContentControl x:Name="MainRegion"
                    Grid.Row="1"
                    Grid.Column="1"
                    regions:RegionManager.RegionName="MainRegion" />
</Grid>

I mentioned the whole 'region' thing before, so you must be wondering what 'regions:RegionManager.RegionName=""' is all about.  This works with a RegionManager in Prism to determine where on your page a view will display.  Also for reference, the regions namespace is coming from 'clr-namespace:Microsoft.Practices.Composite.Presentation.Regions'.  Once we dive into modules a bit in the next post you'll see where these regions come into play.

The last step to get a fully functional husk of a Prism application going is to do a little modification to the App.xaml.cs, which holds our startup and shut down logic for the application.  Normally you'd see some of that rootvisual logic that we put into the BootStrapper in the App.xaml.cs, so we've got to replace that with...

private void Application_Startup(object sender, StartupEventArgs e)
{           
    Bootstrapper bootstrapper = new Bootstrapper();
    bootstrapper.Run();
}

One other tiny note, since I wanted to use our awesome Windows 7 theme across the application, I also included this line in the public App() area just above startup, right above the InitializeComponent() call:

StyleManager.ApplicationTheme = new Windows7Theme();

 

Setting up the Code-Behind Project

Things are infinitely quicker to setup for the code-behind project, which is going to look like this from the get-go:

RecruitCB Project Startup

Since we aren't using Prism we don't have to worry about a Shell, a BootStrapper, or starting our BootStrapper in the App.xaml.cs (although we are still adding the StyleManager line for our Application-wide Windows 7 theme), which means all we're worrying about is the MainPage.Xaml- and we don't even have to change the name to Shell!  One of the nicest things too is that I already designed my Shell.Xaml, so I can copy and paste the entire code snippit above into MainPage.Xaml and have a working UI in seconds.  The only real change I need to make is to strip out 'region' references, so the changed part of the xaml code now looks like:

<!-- Notifications Region -->
<ContentControl x:Name="NotificationRegion"
                HorizontalAlignment="Right"
                Grid.Column="1" />
<!-- Menu Region -->
<ContentControl x:Name="MenuRegion"
                Grid.Row="1" />
<!-- Main Content Region -->
<ContentControl x:Name="MainRegion"
                Grid.Row="1"
                Grid.Column="1" />

Right now the line of thought is that since I can set the .Content of a ContentControl, I can either load separate Xaml UserControls into those placeholders (possible option) or instead build out the menu and notification area in the XAML and just use the MainRegion ContentControl for loading different controls or views that I will need.  That would let me load things as I please and easily handle switching between sections of the application without much effort.

Part 3 - The End Result

While I am going to have to put a bit more plumbing into the Prism version to get it read for things like commands, events, and swapping views, we basically have the core UI setup and both projects in the form that we can run them and get a nice UI running in my browser:

Side-by-side comparison

Pretty neat, don't you think?  Next time, we're going to look at actually getting some functionality in here.  For the Recruit (Prism project), that means setting up an Infrastructure project and laying the groundwork for my modules as well as the WCF RIA Services link, whereas for RecruitCB (code-behind project) I'll have to setup WCF RIA Services and make a few control shells for where I'll be implementing functionality down the road.


About the Author

Evan Hutnick

works as a Developer Evangelist for Telerik specializing in Silverlight and WPF in addition to being a Microsoft MVP for Silverlight. After years as a development enthusiast in .Net technologies, he has been able to excel in XAML development helping to provide samples and expertise in these cutting edge technologies. You can find him on Twitter @EvanHutnick.

Related Posts

Comments