Template Selector in a ToolWindow

Docking/MDI for WPF Forum

Posted 5 months ago by Justin Klein
Version: 19.1.0681
Avatar

I'm sure I'm just missing something extremely basic/obvious, but I can't seem to get a DataTemplate selector working in a ToolWindow (it works fine in the TabbedMdiHost).  Here's the relevant section:

<actidock:DockSite x:Name="dockSite" ...>
....

    <actidock:SplitContainer>

        <actidock:ToolWindowContainer>
            <actidock:ToolWindow Title="Doc" DataContext="{Binding ElementName=dockSite, Path=DataContext.ActiveDocViewModel}" >
                <actidock:ToolWindow.Resources>
                    <DataTemplate DataType="{x:Type local:MyDocViewModel}">
                        <TextBlock>Selected!</TextBlock>
                    </DataTemplate>
                </actidock:ToolWindow.Resources>
             </actidock:ToolWindow>
        </actidock:ToolWindowContainer>

        <actidock:Workspace>
        ....
        </actidock:Workspace>
    </actidock:SplitContainer>
</actidock:DockSite>

Above shows nothing in the ToolWindow (no matter what DataType is there).  However, if I just spit out the DataContext, it does show the expected text ("MyNamespace.MyDocViewModel"):

<actidock:ToolWindowContainer>
    <actidock:ToolWindow Title="Doc" DataContext="{Binding ElementName=dockSite, Path=DataContext.ActiveDoc}" >
        <TextBlock Text="{Binding}"/>
    </actidock:ToolWindow>
</actidock:ToolWindowContainer>

Any pointers on what simple thing I might be missing?

Thanks in advance :)

Comments (13)

Posted 5 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Justin,

I would suggest putting your DataTemplate at the DockSite.Resources (or App.Resources if the former still doesn't work) level instead.  See if that helps.  My guess is that it won't be found when it's in Resources within the nested hierarchy of the DockSite.


Actipro Software Support

Posted 5 months ago by Justin Klein
Avatar

Hi,

Thanks for the quick reply.  Unfortunately, even moving the DataTemplates to App.Resources didn't seem to make a difference :/

Posted 5 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

While we do mimic a lot of ItemsControl functionality in terms of MVVM with DockSite, it doesn't inherit ItemsControl directly and perhaps the DataType'd DataTemplates is a feature that is lost in that translation.

I'd suggest setting the DockSite.DocumentItemTemplateSelector or ToolItemTemplateSelector properties and making a DataTemplateSelector that works the same as those for normal ItemsControls.  That way you can build a SelectTemplate method that looks at the data item and returns an appropriate DataTemplate.  Ideally the DataTemplate is in your App.Resources.


Actipro Software Support

Posted 5 months ago by Justin Klein
Avatar

>>perhaps the DataType'd DataTemplates is a feature that is lost in that translation

Understood.  Before I go this route though, is there a way to confirm that that's definitely the case?  It would be a shame to implement the more roundabout solution, but then learn that actually it wasn't missing, there was just some other little thing I overlooked & and we could've just stuck with MVVM after all.

>>making a DataTemplateSelector that works the same as those for normal ItemsControls

Pending the above, could you point me to where in the sample code I might find an example of this?

Thanks :)

Posted 5 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

I looked and we do actually support and use implicit DataType-based DataTemplates in the MvvmDocumentWindows QuickStart in the MainView.Xaml.

The MvvmToolWindows QuickStart shows a DataTemplateSelector example in MainView.xaml.


Actipro Software Support

Posted 5 months ago by Justin Klein
Avatar

>>I looked and we do actually support and use implicit DataType-based DataTemplates in the MvvmDocumentWindows QuickStart in the MainView.Xaml.

Right - for the documents themselves (which I'm also successfully using in my app - mine are in TabbedMdiHost.Resources, which works great even for tear-out windows).  Is this also supported for ToolWindows, though?

>>The MvvmToolWindows QuickStart shows a DataTemplateSelector example in MainView.xaml.

Perfect example of that approach, thanks.  Does the existence of this approach here - rather than using DataType-based DataTemplates - imply that that approach is only supported for docs, and not toolwindows?

Thanks again

Posted 5 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

The same approach should work for tool windows too.  I updated our MvvmToolWindows QuickStart to use DataType-based DataTemplates instead of using a DataTemplateSelector and it worked fine.  

I believe we showed a different approach in two QuickStarts to show examples of the two ways of doing this.


Actipro Software Support

Posted 5 months ago by Justin Klein
Avatar

Alright, well at least that provides an easy way for me to show you exactly what I'm seeing :)  Here's a drop-in full replacement for MVVMToolWindows MainView.xaml that shows what I'm trying to accomplish (see code comments below - perhaps easier if you diff vs the original file, there are only minimal changes):

<UserControl x:Class="ActiproSoftware.ProductSamples.DockingSamples.QuickStart.MvvmToolWindows.MainView"
		xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
		xmlns:common="clr-namespace:ActiproSoftware.ProductSamples.DockingSamples.Common"
		xmlns:docking="http://schemas.actiprosoftware.com/winfx/xaml/docking"
		xmlns:sample="clr-namespace:ActiproSoftware.ProductSamples.DockingSamples.QuickStart.MvvmToolWindows"
		xmlns:shared="http://schemas.actiprosoftware.com/winfx/xaml/shared"
		>

    <UserControl.Resources>
		
		<common:ToolItemDockSideConverter x:Key="ToolItemDockSideConverter" />
		<common:ToolItemStateConverter x:Key="ToolItemStateConverter" />

        <Style x:Key="DockingWindowStyle" TargetType="docking:DockingWindow">
            <Setter Property="Description" Value="{Binding Path=Description, Mode=TwoWay}" />
            <Setter Property="ImageSource" Value="{Binding Path=ImageSource, Mode=TwoWay}" />
            <Setter Property="IsActive" Value="{Binding Path=IsActive, Mode=TwoWay}" />
            <Setter Property="IsFloating" Value="{Binding Path=IsFloating, Mode=TwoWay}" />
            <Setter Property="IsOpen" Value="{Binding Path=IsOpen, Mode=TwoWay}" />
            <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
            <Setter Property="SerializationId" Value="{Binding Path=SerializationId, Mode=TwoWay}" />
            <Setter Property="Title" Value="{Binding Path=Title, Mode=TwoWay}" />
            <Setter Property="WindowGroupName" Value="{Binding Path=WindowGroupName, Mode=TwoWay}" />
        </Style>

        <Style x:Key="ToolWindowStyle" TargetType="docking:ToolWindow" BasedOn="{StaticResource DockingWindowStyle}">
            <Setter Property="DefaultDockSide" Value="{Binding Path=DefaultDockSide, Mode=TwoWay, Converter={StaticResource ToolItemDockSideConverter}}" />
            <Setter Property="State" Value="{Binding Path=State, Mode=TwoWay, Converter={StaticResource ToolItemStateConverter}}" />
        </Style>

        <sample:ToolItemTemplateSelector x:Key="ToolItemTemplateSelector">
            <sample:ToolItemTemplateSelector.ToolItem1Template>
                <DataTemplate>
                    <sample:ToolItem1View />
                </DataTemplate>
            </sample:ToolItemTemplateSelector.ToolItem1Template>
            <sample:ToolItemTemplateSelector.ToolItem2Template>
                <DataTemplate>
                    <sample:ToolItem2View />
                </DataTemplate>
            </sample:ToolItemTemplateSelector.ToolItem2Template>
            <sample:ToolItemTemplateSelector.ToolItem3Template>
                <DataTemplate>
                    <sample:ToolItem3View />
                </DataTemplate>
            </sample:ToolItemTemplateSelector.ToolItem3Template>
        </sample:ToolItemTemplateSelector>
		
    </UserControl.Resources>

    <!-- DockSite -->
    <docking:DockSite x:Name="dockSite"
					  ToolItemContainerStyle="{StaticResource ToolWindowStyle}"
					  >
        <docking:SplitContainer>
            
            <docking:ToolWindowContainer>
                
                <!--Just for information, to confirm the type of our current VM-->
                <docking:ToolWindow Title="ToolItemTest" >
                    <WrapPanel>
                        <TextBlock>Our VM is: </TextBlock>
                        <TextBlock Text="{Binding}"/>
                    </WrapPanel>
                </docking:ToolWindow>

                <!--As expected, this works (explicitly setting the ToolWindow's template)-->
                <docking:ToolWindow Title="Set Explicitly" >
                    <docking:ToolWindow.ContentTemplate>
                        <DataTemplate>
                            <sample:ToolItem1View />
                        </DataTemplate>
                    </docking:ToolWindow.ContentTemplate>
                </docking:ToolWindow>

                <!--This is what I'm trying to do: set the DataTemplate of the ToolWindow based on the type of ViewModel.  It's coming up empty/blank.-->
                <docking:ToolWindow Title="Set By DataType">
                    <docking:ToolWindow.Resources>
                        <DataTemplate DataType="{x:Type sample:MainViewModel}">
                            <TextBlock>Set Via DataType</TextBlock>
                        </DataTemplate>
                    </docking:ToolWindow.Resources>
                </docking:ToolWindow>
                
            </docking:ToolWindowContainer>

            <docking:Workspace>
                <docking:TabbedMdiHost>
                    <docking:TabbedMdiContainer>
                        <docking:DocumentWindow Title="Tools List" ImageSource="/Resources/Images/DocumentOutline16.png">
                            <ListView ItemsSource="{Binding ElementName=dockSite, Path=ToolItemsSource}" SelectedIndex="0" BorderThickness="0">
                                <ListView.View>
                                    <GridView>
                                        <GridViewColumn Width="150" Header="Title" DisplayMemberBinding="{Binding Title}" />
                                        <GridViewColumn Width="60" Header="Is Open" DisplayMemberBinding="{Binding IsOpen}" />
                                        <GridViewColumn Width="80" Header="Is Selected" DisplayMemberBinding="{Binding IsSelected}" />
                                        <GridViewColumn Width="60" Header="Is Active" DisplayMemberBinding="{Binding IsActive}" />
                                        <GridViewColumn Width="60" Header="Is Floating" DisplayMemberBinding="{Binding IsFloating}" />
                                    </GridView>
                                </ListView.View>
                            </ListView>
                        </docking:DocumentWindow>
                    </docking:TabbedMdiContainer>
                </docking:TabbedMdiHost>
            </docking:Workspace>
        </docking:SplitContainer>
    </docking:DockSite>

</UserControl>
Posted 5 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Justin,

Thanks for the sample.  The DataType-based DataTemplates will only work if you define them at or above the DockSite level and also you need to be using MVVM for your tool windows via the DockSite.ToolItemsSource property.  Whereas in this sample you are explicitly defining the ToolWindow in the DockSite.

To get your sample to work, you'd need to use ToolItemsSource like we do in our version of it.  You could remove the DockSite.ToolItemTemplateSelector property setting we have.  Then you'd need to add DataTemplates like this in the UserControl.Resources:

<DataTemplate DataType="{x:Type sample:ToolItem3ViewModel}">
	<sample:ToolItem3View />
</DataTemplate>

That would get MVVM working with DataType-based DataTemplates.


Actipro Software Support

Posted 5 months ago by Justin Klein
Avatar

Ahhh, got it - thanks!

Posted 5 months ago by Justin Klein
Avatar

I've successfully converted it to using ToolItemsSource & DataType-based DocTemplates, and everything works perfectly with just one exception: it doesn't seem to respect the IsSelected setting.  i.e.:

ToolItems.Add(new Panel3DViewModel() { Title = "3D", IsSelected=false });
ToolItems.Add(new Panel2DViewModel() { Title = "2D", IsSelected=true });

In the above case, it comes up with 3D selected, not 2D (screenshot: http://take.ms/MPInS).  I'm certain that IsSelected is bound properly, as if setup a Command letting me toggle it later, it works.  But I'd like it to come up preselected, per above.

(Side note: the ToolWindows also seem to come up in backwards-order from how they were added to ToolItems...but that's obviously easy to solve, by just reversing the order I add them.)

Posted 5 months ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Justin,

What if you added the ToolItems and then set IsSelected in code on the "2D" view model right after?  Does that work?

There is a DockSite.AreNewTabsInsertedBeforeExistingTabs property you can toggle that determines if new tabs appear on the left or not.


Actipro Software Support

Posted 5 months ago by Justin Klein
Avatar

If I set IsSelected in i.e. a Window.Loaded event, it works.  It just doesn't work properly if I do it in the MainWindowViewModel's ctor (which is where I setup everything else - aka all other properties work properly there: title, default dock side, docked size, state, etc).

However, it looks like I can workaround the issue by using AreNewTabsInsertedBeforeExistingTabs & just inserting in a different order.

Thanks,

J~

The latest build of this product (v2019.1 build 0683) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.