Place toolwindow tabs on the left side of the container

Docking/MDI for WPF Forum

Posted 16 years ago by Bjørnar Sundsbø - Norway
Version: 4.5.0483
Avatar
Hi

I'm trying to change the template of the ToolWindowContainer to display the tabs for the tool windows on one side of the container. Using Features (in-line) from the Docking & MDI samples as a guide, I want to place the Solution Explorer, Class View and Document Outline on the left/right side instead of on the bottom.

I've tried to change the default template for a few hours, but no major success. What I have tried so far, is adding two columns to the rootGrid in the ControlTemplate, and place ToolWindowTabPanel and tabPanelBorder in column 0, and tried to add a RotateTransform with a 90 degree angle (RenderTransformOrigin="0.5,0.5"). This works somewhat, but it doesn't look very nice. The items inside the ToolWindowTabPanel seems to be the toolwindow itself, and not the button, or something.

I want to be able to easily make the control template display the tabs on either left, right or bottom.

Is there anyone who can help me out with this?

Best regards,
Bjørnar Sundsbø


Bjørnar Sundsbø

Comments (17)

Posted 16 years ago by Bjørnar Sundsbø - Norway
Avatar
I have created a custom ToolWindowContainer with a property DockDirection (of type Dock) and the following control template. It works very well.

            <ControlTemplate TargetType="{x:Type Controls:DockableToolWindowContainer}">
                    <ControlTemplate.Resources>
                        <Style x:Key="{x:Type docking:ToolWindow}" TargetType="{x:Type docking:ToolWindow}">
                            <Style.BasedOn>
                                <Style TargetType="{x:Type docking:ToolWindow}">
                                    <Setter Property="Background" Value="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabBackgroundNormal, TypeInTargetAssembly={x:Type docking:DockSite}}}"/>
                                    <Setter Property="BorderBrush" Value="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabBorderNormal, TypeInTargetAssembly={x:Type docking:DockSite}}}"/>
                                    <Setter Property="BorderThickness" Value="1,1,1,1"/>
                                    <Setter Property="Foreground" Value="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabForegroundNormal, TypeInTargetAssembly={x:Type docking:DockSite}}}"/>
                                    <Setter Property="Margin" Value="0,0,-1,2"/>
                                    <Setter Property="Padding" Value="2,2,4,2"/>
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate TargetType="{x:Type docking:ToolWindow}">
                                                <Grid>
                                                    <Border x:Name="border" ClipToBounds="True" SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="0,0,3,3">
                                                        <shared:PixelSnapper>
                                                            <DockPanel LastChildFill="True">
                                                                <Image Margin="2,2,0,2" x:Name="image" VerticalAlignment="Center" Width="16" Height="16" SnapsToDevicePixels="True" Source="{TemplateBinding ImageSource}" Stretch="UniformToFill" DockPanel.Dock="Left" AutomationProperties.Name="Image"/>
                                                                <docking:TruncationDecorator IsTruncated="{Binding Path=IsTitleTruncated, Mode=OneWayToSource, RelativeSource={RelativeSource TemplatedParent}}">
                                                                    <TextBlock Margin="{TemplateBinding Padding}" VerticalAlignment="Center" SnapsToDevicePixels="True" Text="{TemplateBinding Title}" TextTrimming="CharacterEllipsis" AutomationProperties.Name="Title"/>
                                                                </docking:TruncationDecorator>
                                                            </DockPanel>
                                                        </shared:PixelSnapper>
                                                    </Border>
                                                    <Border x:Name="highlight" VerticalAlignment="Bottom" Height="3" SnapsToDevicePixels="True" Visibility="Collapsed" Background="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabHighlight, TypeInTargetAssembly={x:Type docking:DockSite}}}" CornerRadius="0,0,3,3"/>
                                                </Grid>
                                                <ControlTemplate.Triggers>
                                                    <Trigger Property="ImageSource" Value="{x:Null}">
                                                        <Setter Property="Visibility" TargetName="image" Value="Collapsed"/>
                                                    </Trigger>
                                                    <Trigger Property="IsMouseOver" Value="True">
                                                        <Setter Property="Background" Value="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabBackgroundHover, TypeInTargetAssembly={x:Type docking:DockSite}}}"/>
                                                        <Setter Property="BorderBrush" Value="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabBorderHover, TypeInTargetAssembly={x:Type docking:DockSite}}}"/>
                                                        <Setter Property="Foreground" Value="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabForegroundHover, TypeInTargetAssembly={x:Type docking:DockSite}}}"/>
                                                        <Setter Property="Visibility" TargetName="highlight" Value="Visible"/>
                                                    </Trigger>
                                                    <Trigger Property="IsSelected" Value="True">
                                                        <Setter Property="Background" Value="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabBackgroundSelected, TypeInTargetAssembly={x:Type docking:DockSite}}}"/>
                                                        <Setter Property="Foreground" Value="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabForegroundSelected, TypeInTargetAssembly={x:Type docking:DockSite}}}"/>
                                                        <Setter Property="BorderBrush" Value="{DynamicResource {ComponentResourceKey ResourceId=ToolWindowTabBorderSelected, TypeInTargetAssembly={x:Type docking:DockSite}}}"/>
                                                        <Setter Property="BorderThickness" Value="1,0,1,1"/>
                                                        <Setter Property="Margin" Value="0,0,-1,0"/>
                                                        <Setter Property="Padding" TargetName="border" Value="0,1,0,0"/>
                                                        <Setter Property="Visibility" TargetName="highlight" Value="Visible"/>
                                                    </Trigger>
                                                    <Trigger Property="IsTitleTruncated" Value="True">
                                                        <Setter Property="ToolTip" TargetName="border" Value="{Binding Path=Title, RelativeSource={RelativeSource TemplatedParent}}"/>
                                                    </Trigger>
                                                </ControlTemplate.Triggers>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                    <Style.BasedOn>
                                        <Style TargetType="{x:Type docking:DockingWindow}">
                                            <Setter Property="AutomationProperties.Name" Value="{Binding Path=Title, RelativeSource={RelativeSource Self}}"/>
                                            <Setter Property="Template">
                                                <Setter.Value>
                                                    <ControlTemplate TargetType="{x:Type docking:DockingWindow}">
                                                        <ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
                                                    </ControlTemplate>
                                                </Setter.Value>
                                            </Setter>
                                        </Style>
                                    </Style.BasedOn>
                                </Style>
                            </Style.BasedOn>
                        </Style>
                        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>

                    </ControlTemplate.Resources>
                    <Grid x:Name="splitterGrid">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>

                        <Grid x:Name="tabPanelGrid" Grid.Column="1" Grid.Row="2">
                            <Border x:Name="tabPanelBorder" VerticalAlignment="Top" Height="3" SnapsToDevicePixels="True" Background="{TemplateBinding TabBarSpacerBackground}" BorderBrush="{TemplateBinding TabBarSpacerBorderBrush}" BorderThickness="0,0,0,1" >
                                <Border.Visibility>
                                    <Binding Path="IsTabBarVisible" RelativeSource="{RelativeSource TemplatedParent}">
                                        <Binding.Converter>
                                            <BooleanToVisibilityConverter/>
                                        </Binding.Converter>
                                    </Binding>
                                </Border.Visibility>
                            </Border>

                            <docking:ToolWindowTabPanel Margin="0,2,0,1" x:Name="PART_ItemsHost" ClipToBounds="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsItemsHost="True">
                                <docking:ToolWindowTabPanel.Visibility>
                                    <Binding Path="IsTabBarVisible" RelativeSource="{RelativeSource TemplatedParent}">
                                        <Binding.Converter>
                                            <BooleanToVisibilityConverter/>
                                        </Binding.Converter>
                                    </Binding>
                                </docking:ToolWindowTabPanel.Visibility>
                            </docking:ToolWindowTabPanel>
                        </Grid>

                        <Grid x:Name="rootGrid" Grid.Column="1" Grid.Row="1">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>
                            <shared:PixelSnapper>
                                <Border x:Name="titleBarBorder" SnapsToDevicePixels="True" Background="{TemplateBinding TitleBarBackgroundInactive}" BorderBrush="{TemplateBinding TitleBarBorderInactiveBrush}" BorderThickness="{TemplateBinding TitleBarBorderThickness}" CornerRadius="{TemplateBinding TitleBarBorderCornerRadius}">
                                    <Border.Visibility>
                                        <Binding Path="SelectedItem.HasTitleBarResolved" RelativeSource="{RelativeSource TemplatedParent}">
                                            <Binding.Converter>
                                                <BooleanToVisibilityConverter/>
                                            </Binding.Converter>
                                        </Binding>
                                    </Border.Visibility>
                                    <DockPanel Margin="{TemplateBinding Padding}" x:Name="PART_TitleBar" Background="#00FFFFFF" LastChildFill="True">
                                        <docking:TitleBarButton x:Name="closeButton" ToolTip="Close" Focusable="False" CommandTarget="{Binding Path=., RelativeSource={RelativeSource TemplatedParent}}" DockPanel.Dock="Right" AutomationProperties.Name="Close">
                                            <docking:TitleBarButton.Command>
                                                <RoutedUICommand Text="Close"/>
                                            </docking:TitleBarButton.Command>
                                            <docking:TitleBarButton.Visibility>
                                                <Binding Path="SelectedItem.CanCloseResolved" RelativeSource="{RelativeSource TemplatedParent}">
                                                    <Binding.Converter>
                                                        <BooleanToVisibilityConverter/>
                                                    </Binding.Converter>
                                                </Binding>
                                            </docking:TitleBarButton.Visibility>
                                            <Canvas Width="12" Height="12">
                                                <Path Fill="{Binding Path=Foreground, ElementName=closeButton}" Stretch="Fill" Width="8" Height="8" Data="M0,0L1,0 4,3 7,0 8,0 8,1 5,4 8,7 8,8 7,8 4,5 1,8 0,8 0,7 3,4 0,1z" Canvas.Left="2" Canvas.Top="2"/>
                                            </Canvas>
                                        </docking:TitleBarButton>
                                        <docking:TitleBarButton x:Name="autoHideButton" ToolTip="Auto Hide" Focusable="False" CommandTarget="{Binding Path=., RelativeSource={RelativeSource TemplatedParent}}" DockPanel.Dock="Right" AutomationProperties.Name="Auto-Hide">
                                            <docking:TitleBarButton.Command>
                                                <RoutedUICommand Text="Auto Hide"/>
                                            </docking:TitleBarButton.Command>
                                            <docking:TitleBarButton.Visibility>
                                                <Binding Path="SelectedItem.CanAutoHideResolved" RelativeSource="{RelativeSource TemplatedParent}">
                                                    <Binding.Converter>
                                                        <BooleanToVisibilityConverter/>
                                                    </Binding.Converter>
                                                </Binding>
                                            </docking:TitleBarButton.Visibility>
                                            <Grid>
                                                <Canvas x:Name="pinnedGlyph" Width="12" Height="12">
                                                    <Path Fill="{Binding Path=Foreground, ElementName=closeButton}" Stretch="Fill" Width="7" Height="10" Data="F1M2,7L3,7 3,1 8,1 8,7 6,7 6,2 4,2 4,7 9,7 9,8 6,8 6,11 5,11 5,8 2,8" Canvas.Left="2" Canvas.Top="1"/>
                                                </Canvas>
                                                <Canvas x:Name="unpinnedGlyph" Width="12" Height="12" Visibility="Collapsed">
                                                    <Path Fill="{Binding Path=Foreground, ElementName=closeButton}" Stretch="Fill" Width="10" Height="7" Data="F1M5,3L5,4 11,4 11,9 5,9 5,7 10,7 10,5 5,5 5,7 5,10 4,10 4,7 1,7 1,6 4,6 4,3" Canvas.Left="1" Canvas.Top="3"/>
                                                </Canvas>
                                            </Grid>
                                        </docking:TitleBarButton>
                                        <docking:TitleBarButton x:Name="optionsButton" ToolTip="Options" Focusable="False" CommandParameter="{Binding RelativeSource={RelativeSource Self}}" CommandTarget="{Binding Path=., RelativeSource={RelativeSource TemplatedParent}}" DockPanel.Dock="Right" DisplayMode="PopupOnly" AutomationProperties.Name="Options">
                                            <docking:TitleBarButton.Visibility>
                                                <Binding Path="SelectedItem.HasOptionsResolved" RelativeSource="{RelativeSource TemplatedParent}">
                                                    <Binding.Converter>
                                                        <BooleanToVisibilityConverter/>
                                                    </Binding.Converter>
                                                </Binding>
                                            </docking:TitleBarButton.Visibility>
                                            <docking:TitleBarButton.Command>
                                                <RoutedUICommand Text="Options"/>
                                            </docking:TitleBarButton.Command>
                                            <Canvas Width="12" Height="12">
                                                <Path Fill="{Binding Path=Foreground, ElementName=closeButton}" Stretch="Fill" Width="8" Height="4" Data="F1M2,6.01038L10,6 6.39404,9.55326 6.3947,10 5.6036,10 5.60293,9.55326 2,6.01038z" Canvas.Left="2" Canvas.Top="6"/>
                                            </Canvas>
                                        </docking:TitleBarButton>
                                        <shared:PixelSnapper VerticalAlignment="Center">
                                            <shared:ZeroSizeContentControl ClipToBounds="True" HasWidth="False">
                                                <TextBlock Margin="3,1,2,1" x:Name="title" Foreground="{TemplateBinding TitleBarForegroundInactive}" Text="{Binding Path=SelectedItem.Title, RelativeSource={RelativeSource TemplatedParent}}" TextTrimming="CharacterEllipsis" AutomationProperties.Name="Title"/>
                                            </shared:ZeroSizeContentControl>
                                        </shared:PixelSnapper>
                                    </DockPanel>
                                </Border>
                            </shared:PixelSnapper>
                            <Border SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Grid.Row="1">
                                <shared:TransitionPresenter x:Name="PART_SelectedContentHost" Content="{Binding Path=SelectedContent, RelativeSource={RelativeSource TemplatedParent}}" DefaultDuration="00:00:00.1500000" TransitionSelector="{TemplateBinding docking:DockSite.ToolWindowTransitionSelector}"/>
                            </Border>
                        </Grid>
                    </Grid>
                    <ControlTemplate.Triggers>

                        <Trigger Property="docking:TitleBarButton.IsActive" Value="True">
                            <Setter Property="Background" TargetName="titleBarBorder" Value="{Binding Path=TitleBarBackgroundActive, RelativeSource={RelativeSource TemplatedParent}}"/>
                            <Setter Property="BorderBrush" TargetName="titleBarBorder" Value="{Binding Path=TitleBarBorderActiveBrush, RelativeSource={RelativeSource TemplatedParent}}"/>
                            <Setter Property="Foreground" TargetName="title" Value="{Binding Path=TitleBarForegroundActive, RelativeSource={RelativeSource TemplatedParent}}"/>
                        </Trigger>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding Path=SelectedItem.HasTitleBarResolved, RelativeSource={RelativeSource Self}}" Value="False"/>
                            </MultiDataTrigger.Conditions>
                            <Setter Property="BorderThickness" Value="1,1,1,1"/>
                        </MultiDataTrigger>
                        <Trigger Property="HasSingleWindow" Value="True">
                            <Setter Property="Visibility" TargetName="tabPanelBorder" Value="Collapsed"/>
                            <Setter Property="Visibility" TargetName="PART_ItemsHost" Value="Collapsed"/>
                        </Trigger>
                        <Trigger Property="HasWindows" Value="False">
                            <Setter Property="Visibility" TargetName="rootGrid" Value="Collapsed"/>
                        </Trigger>
                        <Trigger Property="State" Value="AutoHide">
                            <Setter Property="Visibility" TargetName="pinnedGlyph" Value="Collapsed"/>
                            <Setter Property="Visibility" TargetName="unpinnedGlyph" Value="Visible"/>
                        </Trigger>
                        <Trigger Property="DockDirection" Value="Left">
                            <Setter Property="Grid.Column" TargetName="tabPanelGrid" Value="0" />
                            <Setter Property="Grid.Row" TargetName="tabPanelGrid" Value="1" />
                            <Setter Property="LayoutTransform" TargetName="PART_ItemsHost">
                                <Setter.Value>
                                    <RotateTransform Angle="90" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="DockDirection" Value="Top">
                            <Setter Property="Grid.Column" TargetName="tabPanelGrid" Value="1" />
                            <Setter Property="Grid.Row" TargetName="tabPanelGrid" Value="0" />
                        </Trigger>
                        <Trigger Property="DockDirection" Value="Right">
                            <Setter Property="Grid.Column" TargetName="tabPanelGrid" Value="2" />
                            <Setter Property="Grid.Row" TargetName="tabPanelGrid" Value="1" />
                            <Setter Property="LayoutTransform" TargetName="PART_ItemsHost">
                                <Setter.Value>
                                    <RotateTransform Angle="90" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
[Modified at 01/09/2009 05:43 AM]


Bjørnar Sundsbø

Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Bjørnar,

If you'd like us to take a look, please email over a simple project that shows it to our support address. Thanks!


Actipro Software Support

Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Thanks for the sample, to get it working completely correctly I believe we'd need to modify our rendering code-behind for the tabs and possibly a couple other areas in addition to the templates. We'll mark this down as a TODO item.


Actipro Software Support

Posted 16 years ago by Bjørnar Sundsbø - Norway
Avatar
The rotated SmartTab is not really an issue for me, but I just wanted to mention it so you can improve minor glitches in the product.


Bjørnar Sundsbø

Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
We appreciate it. Once we are able to add a dedicated option for the tabs, it should be resolved.


Actipro Software Support

Posted 15 years ago by Aliaksei
Avatar
Hi,
is this problem resolved? How I can change the tab position on toolbox container?
One more question: is it possible to dock tabs from mdicontainer?

Thank you.
Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Aliaksei,

Sorry, while we do have an option to put tabbed MDI tabs on the top or bottom we haven't had a chance to add more options for tool window tabs yet.

I'm not quite sure what you mean about docking tabs from mdicontainer. Tabbed MDI does allow drag/drop within the MDI area. If you have a tool window in the MDI area, you can right click it to say Dockable and that will place it back out in the tool window region so that it can be docked outside of MDI. Hope that answers your question.


Actipro Software Support

Posted 15 years ago by Aliaksei
Avatar
Thank you for your answer. But when I try to move out tool window from mdi container I can't place it back from tool window container to mdi container. Am I wrong?
Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Aliaksei,

Similar to how you used the tool window's context menu to switch to Dockable state, you'd use it again to switch back to Document state to move back to MDI.


Actipro Software Support

Posted 15 years ago by Bjørnar Sundsbø - Norway
Avatar
Hi

Have you been able to dedicate any resources for this?


Bjørnar Sundsbø

Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Bjørnar,

Not for putting tabs on the side. However if you mean easier docking in and out of the MDI area, yes the next version has improvements for that.


Actipro Software Support

Posted 15 years ago by Bjørnar Sundsbø - Norway
Avatar
I meant putting tabs on the side. Any plans for when it is available?


Bjørnar Sundsbø

Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Bjørnar,

The tabs on the side is a lower priority item so we don't really have any timeframe we can provide to you. If it's something very important for you, you can always contract us to implement it. More details on that are here, where you can also request a quote:
http://www.actiprosoftware.com/Purchase/ConsultingServices.aspx


Actipro Software Support

Posted 15 years ago by TRS
Avatar
I am also in need of vertical tabs with vertical text.
Posted 15 years ago by Bjørnar Sundsbø - Norway
Avatar
We have been able to create a substitute for this deriving from ToolWindowContainer, and it seems to be working satisfactory, so it is something we can wait for to be supported in the product.

Based on the number of reads this thread has received, it appears to be something people seem to be curious about.


Bjørnar Sundsbø

Posted 15 years ago by Ben McIntosh
Avatar
I would also very much like to have the option of rendering the tool window tabs on the top. I hope this is added to the product sometime soon.
Posted 14 years ago by Bjørnar Sundsbø - Norway
Avatar
I have fixed this issue. As a quick summary of the requirement, I wish to place the Tabs in the ToolWindowContainer along the edges of the workspace. Toolwindow docked to the left should have the tabs on the left side. Docked on the right should have them on the right hand side. And so on.

The resolution is in the following post.

The only drawback (acceptable) is that if I have docked one or more toolwindows at the bottom of another, and then auto-hide one group, there will be two rows of tabs where the docked tab group will be rendered inside the toolwindow container, and the autohide tabs will be on the AutoHide[Left/Right/Top/Bottom]Container.


Bjørnar Sundsbø

The latest build of this product (v24.1.3) 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.