3

I am making my first WPF application, so this question may seem rather odd. I have been reading about MVVM and so far it has made sense to me. What I don't understand, though, is separating all the XAML.

What I mean is this: I assume you don't place everything in the MainWindow.xaml and just collapse controls based upon what is going to be used. I would think you would want a container that would contain xaml of other files. Is this correct?

How do you go about separating the XAML out so that it isn't just a mash of everything in one file?

Justin
  • 6,373
  • 9
  • 46
  • 72
  • I think your question is rather related to [ResourceDictionaries](http://msdn.microsoft.com/en-us/library/cc903952%28v=VS.95%29.aspx) than to MVVM pattern. – nik Jul 08 '12 at 23:44

3 Answers3

6

How do you go about separating the XAML out so that it isn't just a mash of everything in one file?

There are many ways, including creating a seperate UserControl, CustomControl, Page or Window

For example, if you wanted to pull some XAML out of your MainWindow.xaml, you could create a UserControl (right-click project, Add, New Item..., User Control (WPF)) called MyUserControl.xaml like this:

<UserControl x:Class="WpfApplication1.MyUserControl"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <Grid>
        <TextBlock>This is from a different XAML file.</TextBlock>
    </Grid>
</UserControl>

and then use this control in your MainWindow.xaml like this:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:myControls="clr-namespace:WpfApplication1">
    <Grid>
        <myControls:MyUserControl/>
    </Grid>
</Window>

Note that you need to add a reference to the namespace of your UserControl

xmlns:myControls="clr-namespace:WpfApplication1"
Community
  • 1
  • 1
Kevin Aenmey
  • 13,259
  • 5
  • 46
  • 45
  • So I should switch between various controls that are collapsed/visible in the content of my MainWindow when the user is interacting with my application? – Justin Jul 08 '12 at 23:22
  • 2
    @Justin preferred pattern is to use DataTemplates, see my answer. – Kirk Broadhurst Jul 09 '12 at 00:53
2

I agree with Kevin's answer about UserControl and Window, so I'll just address the follow up question:

So I should switch between various controls that are collapsed/visible in the content of my MainWindow when the user is interacting with my application?

That is a valid option. It might get messy if you are working with a large application.

The other options that I've used are

  • switching Views in the code behind; i.e. on the click events you can add and remove elements from the page as you would have done in WinForms. This is not pure MVVM and some people will jump down your throat, but I believe MVVM is a tool, not a religion.
  • provide Views as properties in your ViewModel, and bind to them from your parent View. I don't know if this is pure MVVM, it's nice when you need to dynamically create Views depending on complex conditions but it can get complicated
  • use DataTemplates, which are essentially rules to determine the View to use based on the type of data that is provided. So if the data is an Address (or AddressViewModel), use the AddressView. If the data is a CustomerViewModel, use the CustomerView. And so on.

DataTemplates are the preferred pattern in my opinion - clean, easy to maintain, and a nice standard. It's trivial to go to the DataTemplate to see how the binding works, whereas the other two options I've given may lead to spaghetti code in the wrong hands.

MSDN has a nice page on DataTemplates in WPF.

Kirk Broadhurst
  • 27,836
  • 16
  • 104
  • 169
1

When using Caliburn framework you could compose your application using smaller Views and ViewModels and have a shell which binds all those smaller views together. The shell would display one or many views at the same time, depending on how you want your application to behave. The good thing about this - unlike the pattern mentioned above where you hardcode the name of the View/UserControl in other places - is that you just create a ContentControl and bind it to the correct ViewModel property and Caliburn will find the correct View for you by convention.

Let's say you have a ShellViewModel and a ShellView which is just an empty window, and another View/ViewModel where you want to display in your shell at one point. You no longer need to instantiate your views anywhere and just work your way using POCO ViewModels objects:

public class ShellViewModel : Screen
{
   public ChildViewModel Child { get; set; }

   public void SomeAction()
   {
       Child = new ChildViewModel(); //Or inject using factory, IoC, etc.
   }
}

public class ShellView : Window
{
}

<Window x:Class="WpfApplication1.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:cal="http://www.caliburnproject.org">
    <Grid>
        <ContentControl cal:View.Model="{Binding Child}" />
    </Grid>
</Window>
Hadi Eskandari
  • 25,575
  • 8
  • 51
  • 65