Silverlight 5 Beta–Combining Implicit Data Templates & Multiple Windows

This was just a little of an “aha” moment for me that I thought I’d share. I was writing a small demo where I have this main Window for my UI and it’s just a DataGrid;

image

and then when you click the Display button I open up a new child window to display that product as in;

image

( don’t ask about the black border around my child window content – I don’t yet know how to get rid of it and I suspect it’s a bug ).

I wrote a little “Window Manager” class that displays the child windows and tries to keep track of them and provides convenience methods like “minimise all” and “restore all” and so on which isn’t very hard in Silverlight 5 and I built this class into a library for convenience. Here’s the class which actually just implements an IWindowManager interface;

image

I wanted to give this class the responsibility of displaying a window via its DisplayContentWindow method and that code looks like this;

  public void DisplayContentWindow(object dataContext)
    {
      if (windows.ContainsKey(dataContext))
      {
        windows[dataContext].WindowState = WindowState.Normal;
        windows[dataContext].Activate();
      }
      else
      {
        Window window = new Window();

        window.Title = string.Format("Child Window {0}",
          this.windows.Keys.Count + 1);

        window.Width = 480;
        window.Height = 640;

        window.Content = new GenericDisplayWindow()
        {
          DataContext = dataContext
        };
        window.Visibility = Visibility.Visible;

        window.Closing += (s, e) =>
          {
            this.windows.Remove(dataContext);
          };

        this.windows[dataContext] = window;
      }
    }

and so this method takes an object and it assumes that you would only want to display the same object in a single window at a time. What it does is;

  1. Check an internal dictionary to see if we already have a Window open for this object. If so, we simply make sure it’s open and activated.
  2. Otherwise, create a new Window for this object and add it to our internal dictionary.

But…here’s the bit that I found “interesting”. When I create the new Window I set its DataContext to the object that was passed to the method – i.e. the new Window becomes the “display” for that object.

But what about the content of the new Window? I came up with something like this;

<UserControl
  x:Class="WindowManagement.GenericDisplayWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d"
  d:DesignHeight="300"
  d:DesignWidth="400">
  <Grid
    x:Name="LayoutRoot">
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition
        Height="Auto" />
    </Grid.RowDefinitions>
    <ContentPresenter
      Content="{Binding}" />
    <Button
      Grid.Row="1"
      HorizontalAlignment="Right"
      Margin="6"
      Content="Close"
      Click="OnClose" />
  </Grid>
</UserControl>

and, for me, the interesting thing about this is the ContentPresenter. What I’m trying to do here is say something like;

“Hey, display this object for me and you figure out what template to use to present the content because I have no idea at this level in my solution”

Now…as long as somewhere in the application there is an implicit template that specifies how to display that type of object then my child window will do the right thing and display it.

And that’s the bit I like Winking smile

In my particular use I have this solution structure where the application has a set of templates in this Template.xaml file;

image

and those templates control how to display items such as this Product;

image

and the underlying WindowManagement library knows nothing about any of that and I can change it completely independently of that library but the ContentPresenter down in that library still knows how to do the right thing and display the content.