If I understand your question ....
I think the approach you can take is to use DataTemplates, ItemsControl, and possibly a ContentPresentor.
In fact, you want to say that WPF "displays" your view models. Since your view models are just classes, WPF does not know how to โrenderโ them. This is where DataTemplates appear. The bonus of this approach is that the DataContext for the contents of the DataTemplate will be automatically set to the view model. DataTemplates are defined in your Window or UserControl resources:
<Window.Resources> <DataTemplate DataType="{x:Type ViewModels:SquareViewModel}"> <Views:SquareView /> </DataTemplate> </Window.Resources>
The above code will display the SquareView control when WPF encounters a SquareViewModel (and set the DataContext to SquareView on SquareViewModel).
To place your view models in a view, you can use ContentPresenter (for one ViewModel):
<ContentPresenter Content="{Binding SingleSquare}" />
In your case, you want a collection of SquareViewModel elements to be displayed, so you want to use ItemsControl:
<ItemsControl ItemsSource="{Binding Squares}" />
This, however, will not give you the desired result, since by default it will act like a ListBox. You will need to apply the template to the ItemsControl to use the main canvas. See this Pete Brown blog for a possible implementation.
Good luck
Edit: additional sample code
Browse Models:
public class MainViewModel { public IEnumerable<SquareViewModel> Squares { get; set; } public MainViewModel() { var squares = new List<SquareViewModel>(); squares.Add(new SquareViewModel(15, 15,100,100, Brushes.CadetBlue, "Square One")); squares.Add(new SquareViewModel(75,125, 80, 80, Brushes.Indigo, "Square Two")); Squares = squares; } } public class SquareViewModel { public int X { get; set; } public int Y { get; set; } public int Width { get; set; } public int Height { get; set; } public Brush Color { get; set; } public string Name { get; set; } public SquareViewModel(int x, int y, int width, int height, Brush color, string name) { X = x; Y = y; Width = width; Height = height; Color = color; Name = name; } }
Views
<UserControl x:Class="MapView.Views.SquareView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <Grid Background="{Binding Color, FallbackValue=Azure}"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Name, FallbackValue=None}" /> </Grid> </UserControl> <Window x:Class="MapView.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ViewModels="clr-namespace:MapView.ViewModels" xmlns:Views="clr-namespace:MapView.Views" Title="Window1" Height="300" Width="300"> <Window.Resources> <DataTemplate DataType="{x:Type ViewModels:SquareViewModel}"> <Views:SquareView /> </DataTemplate> </Window.Resources> <ItemsControl ItemsSource="{Binding Squares}" > <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Beige" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style TargetType="ContentPresenter"> <Setter Property="Canvas.Left" Value="{Binding X}" /> <Setter Property="Canvas.Top" Value="{Binding Y}" /> <Setter Property="Width" Value="{Binding Width}" /> <Setter Property="Height" Value="{Binding Height}" /> </Style> </ItemsControl.ItemContainerStyle> </ItemsControl> </Window>
And in the constructor of Window1:
public partial class Window1 : Window { public Window1() { InitializeComponent(); DataContext = new MainViewModel(); } }