Monday, October 28, 2013

MDI implemention in WPF

I just recently noticed that, there is no MDI (Multiple Document Interface) support in WPF. Microsoft recommends to use TabControl or AvalonDock. However sometimes it could be really useful to see multiple documents in the same time, e.g: during data process. So I decided to develop a one. You can download MDIContainer from here. There is a sample application as well.

How to start
After you downloaded the binary (PDB is also attached), all you need to do is add MDIContainer.Control.dll as reference in your WPF Application. In order to use you need at least .NET 4. MDIContainer does not need any third party or additional references.

Hello MDI
You can decide to use direct content or bind ItemsSource to container. However direct content does not make too much sense. Why do you need closable windows if you have fixed content? So, let's stay by binding. 

<MDI:MDIContainer Margin="4" ItemsSource="{Binding Items}">
    <MDI:MDIContainer.Resources>
        <Style TargetType="{x:Type MDI:MDIWindow}">
            <Setter Property="Title" Value="{Binding Title}" />             
        </Style>
    </MDI:MDIContainer.Resources>
</MDI:MDIContainer>

As you can see, it is similar to the implementation of a TabControl. ItemsSource is also not magic, a simple ObservableCollection<IContent>. You don't have to use IContent interface if you don't want to, you can put there object or your class. It doesn't matter. I prefer to use interfaces in situations like this, to make it more flexible.

public ObservableCollection<IContent> Items { get; private set; }
 
public interface IContent
{
   string Title { get; }
}

There is only one thing left, a user control. Like I wrote, there is no limitation. Create a user control with a view model like you want. Here is a really sample one:

public class PersonWindow : ViewModelBase, IContent
{
  public string Title { get; private set; }

  public PersonWindow(string title)
  {
    this.Title = title;
  }
}

If you don't know how to implement ViewModelBase or what could it be, you can read more here. Currently you can leave it's view empty, but don't forget to set it as DataContext or DataTemplate.

Back to the main window's view model, where you defined the Items. Initialize the Items and add some content:

public MainWindowViewModel()
{
  this.Items = new ObservableCollection<IContent>();
  this.Items.Add(new PersonWindow("Window 1");
  this.Items.Add(new PersonWindow("Window 2");
  this.Items.Add(new PersonWindow("Window 3");
}

Of course this tiny little example does not make too much sense, but shows you how simple to use this control.

You can check it's CodePlex site and download a fully working demo with source code.