Any developer that has used WPF knows that the heart of technology lies in styles and templates. The Infragistics implementation is no different, and they rely on it heavily to achieve theming. Why does this matter to me? One reason. All of these templates and styles are provided to the developers and can be found in the install directory. For example, mine are located in "C:\Program Files (x86)\Infragistics\NetAdvantage 2012.1\WPF\DefaultStyles". With these tools in hand, customization can begin.
Below is my basic implementation of the XamDockManager with MDI tabs.
<igDock:XamDockManager Name="dockManager"> <igDock:DocumentContentHost> <igDock:SplitPane> <igDock:TabGroupPane Name="tabsPane" TabStripPlacement="Top"> <igDock:ContentPane Header="Tab 1" /> </igDock:TabGroupPane> </igDock:SplitPane> </igDock:DocumentContentHost> </igDock:XamDockManager>
The TabGroupPane is the item to focus on. It's the control that provides the reserved space for tab headers and the list/close buttons. The ControlTemplate for TabGroupPane can be found in the directory mentioned above, located in \DockManger\DockManagerGeneric.xaml.
<ControlTemplate x:Key="{x:Static igDock:TabGroupPane.DocumentTabGroupTemplateKey}" TargetType="{x:Type igDock:TabGroupPane}"> <DockPanel ClipToBounds="True" SnapsToDevicePixels="True" KeyboardNavigation.TabNavigation="Local"> <DockPanel x:Name="PART_HeaderArea" Panel.ZIndex="1" DockPanel.Dock="{TemplateBinding TabStripPlacement}"> <DockPanel> <Button x:Name="closeBtn" DockPanel.Dock="Right" Command="{x:Static igDock:TabGroupPane.CloseSelectedItemCommand}" Style="{DynamicResource {x:Static igDock:TabGroupPane.DocumentCloseButtonStyleKey}}" /> <Menu x:Name="filesMenu" DockPanel.Dock="Right" Style="{StaticResource RootMenuStyle}"> <MenuItem x:Name="PART_FilesMenuItem" Style="{DynamicResource {x:Static igDock:TabGroupPane.DocumentFilesMenuItemStyleKey}}" /> </Menu> <!-- AS 9/10/09 TFS19267 - Added CommandParameter --> <Button x:Name="showNavigatorButton" DockPanel.Dock="Right" Visibility="Collapsed" Command="{x:Static igDock:DockManagerCommands.ShowPaneNavigator}" CommandParameter="{TemplateBinding igDock:XamDockManager.DockManager}" Style="{DynamicResource {x:Static igDock:TabGroupPane.DocumentPaneNavigatorButtonStyleKey}}" /> <ItemsPresenter x:Name="PART_TabHeaderPanel" Margin="5,2,10,0" KeyboardNavigation.TabIndex="1"/> </DockPanel> </DockPanel> <Border x:Name="ContentPanel" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.DirectionalNavigation="Contained" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3" BorderBrush="{DynamicResource {x:Static igDock:DockManagerBrushKeys.TabbedPaneOuterBorderFillKey}}" Background="{TemplateBinding Background}" Visibility="Visible" SnapsToDevicePixels="True" > <Border x:Name="InnerBorder" BorderThickness="1" CornerRadius="1" BorderBrush="{DynamicResource {x:Static igDock:DockManagerBrushKeys.TabbedPaneInnerBorderFillKey}}" SnapsToDevicePixels="True" > <Border borderbrush="{DynamicResource {x:Static igDock:DockManagerBrushKeys.TabbedPaneCenterFillKey}}" borderthickness="2" snapstodevicepixels="True" x:name="ThickInnerBorder"> <Border background="{TemplateBinding Background}" borderbrush="{DynamicResource {x:Static igDock:DockManagerBrushKeys.TabbedPaneOuterBorderFillKey}}" borderthickness="1" snapstodevicepixels="True" x:name="InnerMostBorder"> <ContentPresenter ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" x:Name="PART_SelectedContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentTemplateSelector="{TemplateBinding SelectedContentTemplateSelector}" ContentTemplate="{TemplateBinding SelectedContentTemplate}" Content="{TemplateBinding SelectedContent}" /> </Border> </Border> </Border> </Border> </DockPanel> </ControlTemplate>Note that I've omitted the triggers for simplicity. The area to focus on is lines 3-25, where the tab header layout is defined. A DockPanel is used to add the close and menu buttons that appear in the right corner of the control. This is where the new tab button can be added. To add the button, the following line should be added as the last item in the DockManager.
<Button DockPanel.Dock="Left" Style="{StaticResource NewTabButtonStyle}" />That's all it takes. The new tab button now lines up to the right of the right-most tab header.
New tab button |
Squashed new tab button |
<DockPanel DockPanel.Dock="Left" HorizontalAlignment="Left"> <Button DockPanel.Dock="Left" Style="{StaticResource NewTabButtonStyle}" /> <ItemsPresenter x:Name="PART_TabHeaderPanel" Margin="5,2,10,0" KeyboardNavigation.TabIndex="1" DockPanel.Dock="Left" /> </DockPanel>
Now that the layout is working, it's time to address the look and feel of the new tab button. The style referenced, NewTabButtonStyle, is a button style I created for the look and feel I wanted. You can get creative here with the design of the button, but I'd recommend at least using the Infragistics brushes in the style. This keeps the coloring consistent if the theme is changed. For example, I used the following keys for coloring.
- igDock:DockManagerBrushKeys.TabbedDocumentNotActiveOuterBorderFillKey
- igDock:DockManagerBrushKeys.TabbedDocumentNotActiveCenterFillKey
- igDock:DockManagerBrushKeys.TabbedDocumentHottrackCenterFillKey
By using these keys, the new tab button changes colors automatically when the theme of the XamDockManager is changed.
That wraps it up. With these minor modifications and additions, I was able to add a core piece of functionality for my application. A win for both WPF and Infragistics.
Source code: XamDockManager.NewTabButton
Source code: XamDockManager.NewTabButton
No comments:
Post a Comment