When using a ViewModel first MVVM pattern, how can you add your ViewModels to an ObservableCollection so they can be bound into another View and appear as a view?
I’m using AvalonDock, and I’m struggling to bind the LayoutDocument
panes in AvalonDock to my View.
I’m using Stylet as my MVVM framework, but I’ve also tagged it as Caliburn-Micro as I assume my problem is relevant to any ViewModel-First implementation of MVVM.
My test ObservableCollection
is populated as follows:
Documents = new ObservableCollection<LayoutDocument>();
LayoutDocument layout1 = new LayoutDocument();
layout1.Title = "New Document";
UserControl1 control = new UserControl1();
layout1.Content = control;
LayoutDocument layout2 = new LayoutDocument();
layout2.Title = "New Document 2";
HomeViewModel control2 = HomeViewModel;
layout2.Content = control2;
LayoutDocument layout3 = new LayoutDocument();
layout3.Title = "New Document 3";
HomeView control3 = HomeView;
layout3.Content = control3;
Documents.Add(layout1);
Documents.Add(layout2);
Documents.Add(layout3);
UserControl1
is Initialized via InitializeComponent()
in code behind and works perfectly. See image below (first tab).
HomeViewModel
which is how I would like to attach them inline with Stylet requirements has been brought through the constructor and AvalonDock doesn’t seem to recognized it as a ViewModel. It just displays the URL to the ViewModel.
HomeView
(which is a View) has had the code behind deleted, and I would have thought it would be initialized by Stylet. The object has been injected through the constructor. In AvalonDock it’s behaving as an uninitialized view so just shows nothing.
Here is the Constructor:
public DockingViewModel(HomeViewModel homeViewModel, HomeView homeView)
{
HomeViewModel = homeViewModel;
HomeView = homeView;
LoadInitialTabs();
}
I don’t believe the issue is with AvalonDock, but here is how the views are bound.
<DockingManager.LayoutItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding Content , FallbackValue=#ERROR Content.title#}"></ContentControl>
</DataTemplate>
</DockingManager.LayoutItemTemplate>
Note in the image below of the different results when LayoutDocuments
are created in different ways.
How can I get this working in a ViewModel first approach, i.e. using Stylet?
I found the solution. As I am using Stylet I needed to make the following changes in my View.
First, add the reference for Stylet.
xmlns:s="https://github.com/canton7/Stylet"
Second: Change the DataContent binding from:
<ContentControl Content="{Binding Content , FallbackValue=#ERROR Content.title#}"></ContentControl>
To:
<ContentControl s:View.Model="{Binding Content , FallbackValue=#ERROR Content.title#}"></ContentControl>
With Stylet, the s:View.Model
bit automatically finds the View
from the ViewModel
and Initializes it.
Now, I can hold nothing but ViewModels
in my ObservableCollection
and it works fine/