Reputation: 1565
I am using the AvalonDock from the Xceed.Wpf.AvalonDock package (version 3.5). The docking manager is part of my main view. The interesing part is here:
<xcad:DockingManager Name="_dockingManager" Grid.Row="1" DataContext="{Binding DockingManagerViewModel}"
DocumentsSource="{Binding Documents}"
AnchorablesSource="{Binding Anchorables}" >
<xcad:DockingManager.Resources>
<DataTemplate DataType="{x:Type vm:DockingWindowViewModel}">
<v:SampleDockWindowView />
</DataTemplate>
</xcad:DockingManager.Resources>
<xcad:DockingManager.LayoutItemContainerStyle>
<Style TargetType="{x:Type dockctrl:LayoutItem}" >
<Setter Property="Title" Value="{Binding Model.Title}" />
<Setter Property="CloseCommand" Value="{Binding Model.CloseCommand}" />
<Setter Property="CanClose" Value="{Binding Model.CanClose}" />
</Style>
</xcad:DockingManager.LayoutItemContainerStyle>
</xcad:DockingManager>
So the main view model contains an observable collection (e.g. "Documents") where I can add view models dynamically. The problem is now that I have different views for the different view models and the views will be added during runtime. Currently the views are retrieved based on the data templates:
<xcad:DockingManager.Resources>
<DataTemplate DataType="{x:Type vm:DockingWindowViewModel}">
<v:SampleDockWindowView />
</DataTemplate>
</xcad:DockingManager.Resources>
How can I change this to get a dynamic view based on the corresponding view model?
Upvotes: 0
Views: 1311
Reputation: 898
As some people already answered here, you need to add a template selector. So an example may drive you.
Supposing you have 2 couple of view/viewmodel named
MyDocViewA -> MyDocAViewModel
MyDocViewB -> MyDocBViewModel
On the main view XAML code, within you DockingManager
code, you need to add a LayoutItemTemplateSelector
like this:
<xcad:DockingManager.LayoutItemTemplateSelector>
<s:PanesTemplateSelector>
<s:PanesTemplateSelector.MyDocViewATemplate>
<DataTemplate>
<p:MyDocViewA />
</DataTemplate>
</s:PanesTemplateSelector.MyDocViewATemplate>
<s:PanesTemplateSelector.MyDocViewBTemplate>
<DataTemplate>
<p:MyDocViewB />
</DataTemplate>
</s:PanesTemplateSelector.MyDocViewBTemplate>
</xcad:DockingManager.LayoutItemTemplateSelector>
Where s
is the namespace where you define the PanesTemplateSelector
as following:
class PanesTemplateSelector : DataTemplateSelector
{
public DataTemplate MyDocViewATemplate { get; set; }
public DataTemplate MyDocViewBTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is MyDocAViewModel)
return MyDocViewATemplate;
if (item is MyDocBViewModel)
return MyDocViewBTemplate;
}
}
Assuming that MyDocAViewModel
is the ViewModel
for view MyDocViewA
and MyDocBViewModel
is the ViewModel
for view MyDocViewB
.
That's it. Now you can add instances of MyDocAViewModel
and MyDocBViewModel
to your observable collection (eg. "Documents") of your DockingManager
and get it bindinded to MyDocViewA
and MyDocViewB
respectively.
Upvotes: 1
Reputation: 10863
View to view model is normally a one-to-one mapping, so just add a lot of DataTemplate
s... either from xaml or from code or a combination of both (a xaml per module and code in the modules initializer to merge the module's ResourceDictionary
into that of the app).
Upvotes: 0