Silverlight, XAML & Prism: Diving in Head First at the Shallow End of the Pool

Back to Listing

Silverlight, XAML & Prism: Diving in Head First at the Shallow End of the Pool


23 Mar, 2009


My company is investigating a dramatic shift in our product offering. We are looking at offering a SAAS product delivered via Silverlight. Our current offering is a large scale  classic ASP.NET case management system that is installed on site with the client and heavily customized. Our SAAS application is intended to start as a scaled down version of this application.

One of our main goals was to produce a highly modularized application that has been described as "simple widgets of functionality" that are driven by tasks instead of long menu trees. Our source of inspiration is the iPhone and it's clean interface.

Using the amazing Balsamiq, I generated a couple mock ups of a possible UI. I needed something concrete to work toward while learning WPF & Silverlight and modifying my mind set from stateless web mentality.

Desktop

Side Note: Balsamiq is AWESOME. If you have not tried it go now and do it this blog post will wait.

These high level vision statements lead me down the path of a component based UI. I have had a copy of the Composite Application Guidance for WPF sitting on my desk for a couple of months, so I thought I would give that a chance. I then created a separate version of my mock up that described the areas and their function with in the context of a "desktop" screen.

areas

I then downloaded Prism & Unity and with a copy of Silverlight 2 in Action, I began my journey into the bowels of XAML and figuring out exactly how layout works. After a day or so of discovery with the Canvas, Grid & StackPanel controls I came up with this. It's a fairly simple layout consisting of five rows and a hidden control for user notifications. Working with XAML was very difficult for me at first as I wanted to resist table based layouts like the plague due to my HTML bigotry. But once I gave in, I started making progress.

One goal I had was to explore Prism's Region types and how they interact with the UI. In my application shell I had defined regions for each of the major areas of the UI and I wanted to create a "Place Holder" view that I could populate each of the regions with that would give me some information at runtime.

Following the Prism sample code, I created a ApplicationModule class which would represents the Applications role in the UI modularity. This module is the first to load and set default values within the application before moving on to interrogate other assemblies for other modules. One thing the application module does is to set all regions to a default place holder view like so:

public class ApplicationModule : IModule  
{
  private readonly IUnityContainer container;
  private readonly IRegionManager regionManager;
  private readonly IRegionViewRegistry regionViewRegistry;

  public ApplicationModule(IUnityContainer container,
                           IRegionManager regionManager,
                           IRegionViewRegistry regionViewRegistry)
  {
    this.container = container;
    this.regionManager = regionManager;
    this.regionViewRegistry = regionViewRegistry;
  }

  #region IModule Members

  public void Initialize()
  {
    RegisterTypesAndServices();
    RegisterViewsWithRegions();
  }

  private void RegisterViewsWithRegions()
  {
    //registering placeholders with current regions
    this.regionManager.RegisterViewWithRegion(RegionNames.Branding,
                                              () => this.container.Resolve().View);
    this.regionManager.RegisterViewWithRegion(RegionNames.Menu,
                                              () => this.container.Resolve().View);
    this.regionManager.RegisterViewWithRegion(RegionNames.Breadcrumb,
                                              () => this.container.Resolve().View);
    this.regionManager.RegisterViewWithRegion(RegionNames.Content,
                                              () => this.container.Resolve().View);
    this.regionManager.RegisterViewWithRegion(RegionNames.SystemNotification,
                                              () => this.container.Resolve().View);
    this.regionManager.RegisterViewWithRegion(RegionNames.UserNotification,
                                              () => this.container.Resolve().View);

  }

  private void RegisterTypesAndServices()
  {
    this.container.RegisterType();

  }

  #endregion
}

I then wanted my place holder view to display a bit of information about its current context. Specifically I wanted the view to tell me what region it belonged to and its current dimensions. The XAML for this is not even worth looking at, it's a user control with a text block. The problem I ran into was getting any kind of information about the current context of the user control. My first attempt lead me to the VisualTreeHelper class and this code:

var parent = VisualTreeHelper.GetParent(this) as FrameworkElement;  
this.PlaceHolderText.Text = parent.Name ?? "Placeholder";  

This basically left me with a blank screen. Interesting enough the parent of my user control was not the region that contained it but a stack panel with no name that is not even defined in the XAML. It appears that the region is not a UI element so much as a concept within prism. After a couple hours of working with this I was stumped and hit the twitterverse to see if Glenn Block might offer a suggestion.

Glenn was the PM at Microsoft for the Composite Application Guidance for WPF. Seriously his name features prominently on the Authors page. If anyone could point me in the right direction, it would be this guy. It was somewhat of an obvious noob question, but I was very focused on the application DOM. He suggested that I check out the RegionManager.

After fiddling around with the region manager I came up with this:

public partial class PlaceholderView : UserControl, IPlaceholderView  
{
  private IRegionManager regionManager;

  public PlaceholderView(IRegionManager regionManager)
  {
    InitializeComponent();
    this.regionManager = regionManager;
  }

  private void UserControl_Loaded(object sender, RoutedEventArgs e)
  {
    foreach (IRegion region in regionManager.Regions)
    {
      foreach (UserControl view in region.Views)
      {
        if (view == this)
        {
          PlaceHolderText.Text =
            string.Format("{0} PlaceHolder : {1}x{2}",
                          region.Name, view.RenderSize.Width, view.RenderSize.Height);
          return;
        }
      }
    }
  }
}

This almost has me there. For some reason, I get the correct width of the region my user control is inhabiting but the height always reports as zero. I am sure it has to do with how I have structured my application shell and plan to track this one down today.

In the end, I really like Silverlight. Prism allowed me to put something together fast based on a mock up and has DI baked in in a nice way.

Share this story

Bobby Johnson

About Author

I am a passionate engineer with an interest in shipping quality software, building strong collaborative teams and continuous improvement of my skills, team and the product.

comments powered by Disqus
Back to top