Assigning ViewModels to UserControls at runtime and at design time

I think you're overcomplicating things:

What's wrong with:

<Grid IsSharedSizeScope="True">
   <ScrollViewer Margin="8" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True">
      <ItemsControl x:Name="GraphItemsControl" Margin="8"  ItemsSource="{Binding VibeEvents, Mode=OneTime}">
         <ItemsControl.ItemTemplate>
            <DataTemplate>
               <MyShinyUserControl DataContext={Binding}/>
            </DataTemplate>
         </ItemsControl.ItemTemplate>
      </ItemsControl>
   </ScrollViewer>
</Grid>

Bind each VibeEvent to the DataContext of the user control. In the user control itself I'd suggest creating a design-time DataContext to make design easier. Design-Time DataContext looks like this:

<UserControl x:Class="EMC.Windows.AlarmsModule.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:AlarmsModule="clr-namespace:EMC.Windows.AlarmsModule" d:DesignHeight="300"
    d:DesignWidth="300"
             d:DataContext="{d:DesignInstance Type=AlarmsModule:Alarm}"
    >

This gets you to a place where you can build your user control and have design-time data in it. And it's simple and doesn't require much, if any, scaffolding.


Based on Faster Solutions' answer here's the simplest example I can come up with of using a UserControl to display the contents of a list within MVVM Light.

For completeness sake I'll include all the code which I have tried to make as short as possible while still providing design time data that differs from run time data in both the user control's view model and the main view model.

Firstly the locator, VMUCExample/ViewModel/ViewModelLocator.cs:

using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;

namespace VMUCExample.ViewModel
{
    public class ViewModelLocator
    {
        static ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            SimpleIoc.Default.Register<MainViewModel>();
            SimpleIoc.Default.Register<ASquareViewModel>();
        }

        public ASquareViewModel ASquare
        {
            get
            {
                return ServiceLocator.Current.GetInstance<ASquareViewModel>();
            }
        }

        public MainViewModel Main
        {
            get
            {
                return ServiceLocator.Current.GetInstance<MainViewModel>();
            }
        }

        public static void Cleanup() {}
    }
}

I've not used the data service side of MVVM Light, partly to keep things simple. The visible distinction between live data and design time data is handled in the two view model classes.

VMUCExample/ViewModel/ASquareViewModel.cs:

using System.Windows.Media;
using GalaSoft.MvvmLight;

namespace VMUCExample.ViewModel
{
    public class ASquareViewModel : ViewModelBase
    {
        private Brush _SquareColour;
        public Brush SquareColour
        {
            get
            {
                return _SquareColour ?? (_SquareColour = IsInDesignModeStatic ?
                    new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0x78, 0x78)) : // FF7878 (pastel red)
                    new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xBB, 0x78))); // FFBB78 (nectarine)
            }
            set { _SquareColour = value; }
        }
    }
}

So looking at the user control in Expression Blend I see a simple rectangle with pastel red fill:

Blend screenshot with the user control open for editing

The main view model lives in the file VMUCExample/ViewModel/MainViewModel.cs:

using System.Collections.Generic;
using System.Windows.Media;
using GalaSoft.MvvmLight;

namespace VMUCExample.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        private List<ASquareViewModel> _Squares;
        public List<ASquareViewModel> Squares
        {
            get
            {
                if (_Squares == null)
                {
                    _Squares = new List<ASquareViewModel>();
                    var colour = IsInDesignModeStatic ?
                        new SolidColorBrush(Color.FromArgb(0xFF, 0x78, 0xB2, 0xFF)) : // 78B2FF (pastel blue)
                        new SolidColorBrush(Color.FromArgb(0xFF, 0xF9, 0xFF, 0xC7)); // F9FFC7 (eggshell)
                    for (var i = 0; i < 10; i++)
                    {
                        _Squares.Add(new ASquareViewModel {SquareColour = colour});
                    }
                }
                return _Squares;
            }
            set { _Squares = value; }
        }
        public MainViewModel() {}
    }
}

The view for this can also be edited in Expression Blend, but the view model code sets the design time colour data differently:

Blend screenshot with the main window open for editing

These are the two XAML files, firstly VMUCExample/ASquareUC.xaml:

<UserControl x:Class="VMUCExample.ASquareUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d" d:DesignHeight="15" d:DesignWidth="60"
             d:DataContext="{Binding ASquare, Mode=OneWay, Source={StaticResource Locator}}">
    <Grid>
        <Rectangle Fill="{Binding SquareColour}" Margin="2" Width="50" Height="10"/>
    </Grid>
</UserControl>

You can see I've used Faster Solutions' suggestion of putting d:DataContext so that the design time binding I need for Expression Blend when I am designing the user control does not block the data context I need at run-time nor the data context supplied by the parent when I am designing the main window in Expression Blend. I am uncomfortable about this though, it is not the approach characterised as MVVM Light in Paul Stovell's Option 6: A XAML View Model Locator and endorsed by @LBugnion

The other view file is VMUCExample\MainWindow.xaml:

<Window x:Class="VMUCExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vmucExample="clr-namespace:VMUCExample"
        Height="200" Width="100"
        DataContext="{Binding Main, Source={StaticResource Locator}}">
    <Grid x:Name="LayoutRoot">
        <ScrollViewer ScrollViewer.CanContentScroll="True">
            <ItemsControl ItemsSource="{Binding Squares}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <vmucExample:ASquareUC/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl> 
        </ScrollViewer>
    </Grid>
</Window>

The example application itself just draws ten rectangles in a column:

Screenshot of the simple test app

Too simple, I know, but hopefully shows the three potential data sets in use:

  1. Design time for the user control (#FF7878 pastel red),
  2. Design time for the user control set by the main window (#78B2FF pastel blue), and
  3. Run time for the user control set by the main window (#F9FFC7 eggshell).

(N.B. There is another data option, run time for the user control not set by the main window. In this case the user control's view model chooses #FFBB78/nectarine but I didn't need that to explore these bindings.)

For completeness here is the VMUCExample\App.xaml file:

<Application x:Class="VMUCExample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="clr-namespace:VMUCExample.ViewModel"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             StartupUri="MainWindow.xaml"
             mc:Ignorable="d">
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    </Application.Resources>
</Application>