I have a TabControl in a WPF application and sometimes it has one tab row and other times it has two tab rows depending on the width of the parent control. This is certainly the expected behavior for a TabControl.
However I want there to always be two tab rows. Does anyone know how to do this?
Thanks.
<TabControl x:Name="StackOverflowTabControl" HorizontalAlignment="Stretch" Margin="10,10,10,0" VerticalAlignment="Stretch">
<TabItem>
<TabItem.Header>
<TextBlock Text="Hey" FontWeight="SemiBold" />
</TabItem.Header>
<DockPanel VerticalAlignment="Stretch">
<Label Content="Hey" />
</DockPanel>
</TabItem>
<TabItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<TabItem.Header>
<TextBlock Text="Blah" FontWeight="SemiBold" />
</TabItem.Header>
<DockPanel VerticalAlignment="Stretch" >
<Label Content="Hey 2" />
</DockPanel>
</TabItem>
<TabItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<TabItem.Header>
<TextBlock Text="Whatever" FontWeight="SemiBold" />
</TabItem.Header>
<DockPanel VerticalAlignment="Stretch" >
<Label Content="Whatever" />
</DockPanel>
</TabItem>
<TabItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<TabItem.Header>
<TextBlock Text="Info" FontWeight="SemiBold" />
</TabItem.Header>
<DockPanel VerticalAlignment="Stretch" >
<Label Content="Under Construction" HorizontalAlignment="Center" VerticalAlignment="Top" FontSize="24" />
</DockPanel>
</TabItem>
<TabItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<TabItem.Header>
<TextBlock Text="Something" FontWeight="SemiBold" />
</TabItem.Header>
<DockPanel VerticalAlignment="Stretch" >
<Label Content="Hey" />
</DockPanel>
</TabItem>
<TabItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<TabItem.Header>
<TextBlock Text="Nothing" FontWeight="SemiBold" />
</TabItem.Header>
<DockPanel VerticalAlignment="Stretch" >
<Label Content="Hey 3" />
</DockPanel>
</TabItem>
<TabItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<TabItem.Header>
<TextBlock Text="Forms" FontWeight="SemiBold" />
</TabItem.Header>
<DockPanel VerticalAlignment="Stretch" >
<Label Content="Under Construction" HorizontalAlignment="Center" VerticalAlignment="Top" FontSize="24" />
</DockPanel>
</TabItem>
</TabControl>
Right click the TabControl and select EditTemplate->Edit a Copy to get a copy of the template. Then find the TabPanel in the template and add HorizontalAlignment="Left" and MaxWidth=x, where x is the width at which you want the tab items to go to the next line.
Below is an example with a width of 200.
<Window.Resources>
<SolidColorBrush x:Key="TabItem.Selected.Background" Color="#FFFFFF"/>
<SolidColorBrush x:Key="TabItem.Selected.Border" Color="#ACACAC"/>
<Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}">
<Setter Property="Padding" Value="2"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Background" Value="{StaticResource TabItem.Selected.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource TabItem.Selected.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<TabPanel x:Name="headerPanel" Background="Transparent" Grid.Column="0" IsItemsHost="true" Margin="4,0,0,2" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1" MaxWidth="200" HorizontalAlignment="Left"/>
<Border x:Name="contentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="1"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
<Setter Property="Margin" TargetName="headerPanel" Value="2,0,2,2"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="contentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="headerPanel" Value="2,2,0,2"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="headerPanel" Value="1"/>
<Setter Property="Grid.Column" TargetName="contentPanel" Value="0"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="headerPanel" Value="0,2,2,2"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Related
i'm trying to set the Background of the Column Header to a dark grey color (#6A767D) but it doesn´t work. Instead the Header Background is the Color of the AlternatingRowBackground Property. Maybe the Background is somehow overwritten? I'm not sure if you need more than just the xaml-code of the data grid. Any suggestions?
<DataGrid x:Name="DataGrid"
AlternatingRowBackground="#F8F8F8" Margin="40,60,40,45"
Grid.Column="2" Grid.ColumnSpan="10"
Grid.Row="1" Grid.RowSpan="12"
RowHeight="47"
ColumnHeaderHeight="47"
Padding="0"
FontSize="18"
ColumnWidth="Auto"
HorizontalScrollBarVisibility="Visible"
AutoGenerateColumns ="False"
GridLinesVisibility="All"
SelectionUnit="Cell"
ContextMenu="{StaticResource ctMenu}">
<DataGrid.Resources>
<Style x:Key="DatagridColumnHeaderStyle_Basic" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Width" Value="Auto"/>
<Setter Property="Background" Value="#6A767D" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Padding" Value="10" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="TextElement.Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid Name="HedearGrid" Background="AliceBlue" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Margin="6,3,6,3" VerticalAlignment="Center" Grid.Column="0" />
<Path x:Name="SortArrow" Visibility="Collapsed" Data="M0,0 L1,0 0.5,1 z" Stretch="Fill"
Grid.Column="1" Width="8" Height="6" Fill="Blue" Margin="0,0,8,0"
VerticalAlignment="Center" RenderTransformOrigin="0.5,0.4" />
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Cursor="SizeWE"
Grid.Column="1" >
<Thumb.Style>
<Style TargetType="{x:Type Thumb}">
<Setter Property="Width" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Background="Transparent"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Thumb.Style>
</Thumb>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="SortDirection" Value="Ascending">
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
<Setter TargetName="SortArrow" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="SortDirection" Value="Descending">
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<EventSetter Event="MouseUp" Handler="Row_Click"/>
</Style>
</DataGrid.RowStyle>
Two issues:
You never actually assign the style to be used. I would recommend you define the style in the resources of your Window or whatever panel the DataGrid is placed in.
<Window.Resources>
<Style x:Key="DatagridColumnHeaderStyle_Basic" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Width" Value="Auto"/>
<Setter Property="Background" Value="#6A767D" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Padding" Value="10" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="TextElement.Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid Name="HedearGrid" Background="{TemplateBinding Background}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Margin="6,3,6,3" VerticalAlignment="Center" Grid.Column="0" />
<Path x:Name="SortArrow" Visibility="Collapsed" Data="M0,0 L1,0 0.5,1 z" Stretch="Fill"
Grid.Column="1" Width="8" Height="6" Fill="Blue" Margin="0,0,8,0"
VerticalAlignment="Center" RenderTransformOrigin="0.5,0.4" />
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Cursor="SizeWE"
Grid.Column="1" >
<Thumb.Style>
<Style TargetType="{x:Type Thumb}">
<Setter Property="Width" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Background="Transparent"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Thumb.Style>
</Thumb>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="SortDirection" Value="Ascending">
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
<Setter TargetName="SortArrow" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="SortDirection" Value="Descending">
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
You can then assign it to your DataGrid like this:
<DataGrid ColumnHeaderStyle="{StaticResource DatagridColumnHeaderStyle_Basic}"/>
Alternatively, just remove x:Key="DatagridColumnHeaderStyle_Basic", then you don't have to specify.
(fixed for you in the above code) you override your Background with AliceBlue:
<Grid Name="HedearGrid" Background="AliceBlue">
should be:
<Grid Name="HedearGrid" Background="{TemplateBinding Background">
I have a grid with a tab control inside. My goal is to have a list of tabs on the left of screen, which can be scrolled (There is around 10 tabs in typical scenario). I cannot however make it scroll.
What I tried (from other answers here) and didn't work:
Put Height/MaxHeight on my Panels, Grid
Wrapping the whole thing in another panel
Putting my Panel inside ScrollViewer - can't do that since I cannot put something that isn't panel on top of visual tree in ItemsPanelTemplate
Putting the ScrollViewer inside
The base code for the UserControl is here:
<UserControl.Resources>
<converters:StringToByteArrayConverter x:Key="StringToByteArrayConverter" />
<DataTemplate x:Key="GroupTemplate">
<DockPanel Background="{StaticResource LightGreyBrush}">
<Image
Width="210"
Height="240"
DataContext="{Binding DataContext.MyPageModel.MyGraphics.Groups[0], RelativeSource={RelativeSource AncestorType=TabControl, Mode=FindAncestor}}"
DockPanel.Dock="Top"
Source="{Binding Graphic, Converter={StaticResource StringToByteArrayConverter}}" />
<Label
HorizontalAlignment="Center"
Content="{Binding Name}"
DockPanel.Dock="Bottom" />
</DockPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="300" MaxHeight="510" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Grid.Column="0">
<TabControl
ItemTemplate="{StaticResource GroupTemplate}"
ItemsSource="{Binding MyPageModel.MyList.Groups}"
TabStripPlacement="Left">
<TabControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel
CanVerticallyScroll="True"
Orientation="Vertical"
ScrollViewer.CanContentScroll="True"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.IsDeferredScrollingEnabled="False"
ScrollViewer.VerticalScrollBarVisibility="Visible" />
</ItemsPanelTemplate>
</TabControl.ItemsPanel>
</TabControl>
</Grid>
<Grid Grid.Row="1" />
</Grid>
How can I make the tab list scrollable here?
Edit: this is visualization of what I want (roughly, paint skills not good):
Define a custom ControlTemplate where you put a ScrollViewer around the TabPanel.
You will also have to change the Height of the first RowDefinition in your Grid from Auto to *:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="300" MaxHeight="510" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Grid.Column="0">
<TabControl
ItemTemplate="{StaticResource GroupTemplate}"
ItemsSource="{Binding MyPageModel.MyList.Groups}"
TabStripPlacement="Left">
<TabControl.Template>
<ControlTemplate TargetType="{x:Type TabControl}">
<ControlTemplate.Resources>
<SolidColorBrush x:Key="TabItem.Selected.Background" Color="#FFFFFF"/>
<SolidColorBrush x:Key="TabItem.Selected.Border" Color="#ACACAC"/>
</ControlTemplate.Resources>
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="*"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<ScrollViewer>
<TabPanel x:Name="headerPanel" Background="Transparent" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
</ScrollViewer>
<Border x:Name="contentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="1"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
<Setter Property="Margin" TargetName="headerPanel" Value="2,0,2,2"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="contentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="headerPanel" Value="2,2,0,2"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="headerPanel" Value="1"/>
<Setter Property="Grid.Column" TargetName="contentPanel" Value="0"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="headerPanel" Value="0,2,2,2"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</TabControl.Template>
<TabControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel
CanVerticallyScroll="True"
Orientation="Vertical"
ScrollViewer.CanContentScroll="True"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.IsDeferredScrollingEnabled="False"
ScrollViewer.VerticalScrollBarVisibility="Visible" />
</ItemsPanelTemplate>
</TabControl.ItemsPanel>
</TabControl>
</Grid>
<Grid Grid.Row="1" />
</Grid>
I would like to make a contextmenu like the blue one on this image:
I can't figure how to make it so do you have some clues/tutorials/... to share with me?
For now, i'm stuck with this XAML
<Style x:Name="HorizontalContextMenu" TargetType="{x:Type ContextMenu}">
<Setter Property="Background" Value="CadetBlue" />
<Setter Property="BorderBrush" Value="DarkBlue" />
<Setter Property="HorizontalOffset" Value="50"/>
<Setter Property="VerticalOffset" Value="50"/>
<Setter Property="Height" Value="48"/>
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Grid.IsSharedSizeScope" Value="true" />
<Setter Property="HasDropShadow" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Border BorderThickness="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Path Width="100" Height="100"
Data="{DynamicResource RightArrow}"
Fill="Blue" Stretch="Fill"
Grid.Column="0"/>
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.Column="1" Orientation="Horizontal"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
After two days of reflection, i finally achieve this solution:
Frontend XAML
<Button x:Name="btnExpressions" Style="{StaticResource MyMenuButton}" Content="Expressions" Tag="{x:Static iconPacks:PackIconMaterialKind.HeartPulse}" Click="BtnExpressions_Click">
<Button.ContextMenu>
<ContextMenu Style="{StaticResource HorizontalContextMenu}">
<MenuItem Name="BtnA" Header="B" Tag="{x:Static iconPacks:PackIconMaterialKind.RunFast}" Style="{StaticResource HMI}"/>
<MenuItem Name="BtnB" Header="F" Tag="{x:Static iconPacks:PackIconMaterialKind.RunFast}" Style="{StaticResource HMI}"/>
<MenuItem Name="BtnC" Header="T" Tag="{x:Static iconPacks:PackIconMaterialKind.RunFast}" Style="{StaticResource HMI}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
Style XAML
<Style x:Key="HorizontalContextMenu" TargetType="{x:Type ContextMenu}">
<Setter Property="Background" Value="#AF38789E" />
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Height" Value="48"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" Background="Transparent"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu" >
<Border BorderThickness="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Path Data="M0,0.5 L1,0.75 1,0.25Z" Margin="0"
Grid.Column="0"
StrokeThickness="0"
Stroke="{TemplateBinding Background}"
Fill="{TemplateBinding Background}"
Stretch="Fill"
Width="10" Height="20"/>
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"Grid.Column="1" Orientation="Horizontal" Background="{TemplateBinding Background}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="HMI" TargetType="MenuItem">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Opacity" Value="0.5"/>
<Setter Property="Width" Value="48" />
<Setter Property="Height" Value="48" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Border>
<iconPacks:PackIconMaterial Kind="{Binding Tag, RelativeSource={RelativeSource AncestorType=MenuItem}}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Opacity" Value="1" />
</Trigger>
</Style.Triggers>
</Style>
Code behind (VB.NET version)
Private Sub BtnExpressions_Click(sender As Object, e As RoutedEventArgs)
Dim btn As FrameworkElement = sender
If btn IsNot Nothing Then
btn.ContextMenu.PlacementTarget = btn
btn.ContextMenu.Placement = Primitives.PlacementMode.Right
btn.ContextMenu.HorizontalOffset = -10
btn.ContextMenu.VerticalOffset = 0
btn.ContextMenu.IsOpen = True
End If
End Sub
Hope this helps someone else.
Background
I've searched fot a day now, without a good result. What I basically try to achieve is the following treeview:
<Grid>
<TreeView>
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel>
<TextBlock Text="Header Content 1"/>
<TextBlock Text="Header Content 2"/>
</StackPanel>
</TreeViewItem.Header>
<StackPanel >
<TextBlock Margin="-19,0,0,0" Text="Expandable Content 1"/>
<TextBlock Margin="-19,0,0,0" Text="Expandable Content 2"/>
</StackPanel>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel>
<TextBlock Text="Content Footer"/>
<TextBlock Text="Content Footer"/>
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</TreeView>
</Grid>
The Itemspresenter of the treeview should present its content between two content panels (Header & Footer), except that in the code above requires two treeview items and I would like to have it as 1 (selectable) treeview item..
If edited the default Controltemplate of the treeview in an attempt to add a textblock on a third row in a Grid, but for some reason it copies this textblock twice when the treeview item is expanded:
<Window.Resources>
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
<Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid Width="15"
Height="13"
Background="Transparent">
<Path x:Name="ExpandPath"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="1,1,1,1"
Fill="{StaticResource GlyphBrush}"
Data="M 4 0 L 8 4 L 4 8 Z"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Data" TargetName="ExpandPath" Value="M 0 4 L 8 4 L 4 8 Z"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TreeViewItemFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border>
<Rectangle Margin="0,0,0,0"
StrokeThickness="5"
Stroke="Black"
StrokeDashArray="1 2"
Opacity="0"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Padding" Value="1,0,0,0"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19" Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander"
Style="{StaticResource ExpandCollapseToggleStyle}"
IsChecked="{Binding Path=IsExpanded,
RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"/>
<Border Name="Bd"
Grid.Column="1"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Border>
<ItemsPresenter x:Name="ItemsHost"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="Footer Text"></TextBlock>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="false">
<Setter TargetName="ItemsHost"
Property="Visibility"
Value="Collapsed"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="Expander"
Property="Visibility"
Value="Hidden"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasHeader" Value="false"/>
<Condition Property="Width" Value="Auto"/>
</MultiTrigger.Conditions>
<Setter TargetName="PART_Header" Property="MinWidth" Value="75"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasHeader" Value="false"/>
<Condition Property="Height" Value="Auto"/>
</MultiTrigger.Conditions>
<Setter TargetName="PART_Header" Property="MinHeight" Value="19"/>
</MultiTrigger>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/> </Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TreeView>
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel>
<TextBlock Text="Treeview Item 1"/>
<TextBlock Text="Header Content"/>
</StackPanel>
</TreeViewItem.Header>
<StackPanel >
<TextBlock Margin="-19,0,0,0" Text="Expandable Content 1"/>
<TextBlock Margin="-19,0,0,0" Text="Expandable Content 2"/>
</StackPanel>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel>
<TextBlock Text="Treeview Item 2"/>
<TextBlock Text="Header Content"/>
</StackPanel>
</TreeViewItem.Header>
<StackPanel >
<TextBlock Margin="-19,0,0,0" Text="Expandable Content 1"/>
<TextBlock Margin="-19,0,0,0" Text="Expandable Content 2"/>
</StackPanel>
</TreeViewItem>
</TreeView>
</Grid>
In the example above the Footer Content is shown twice because it is added to the bottom of the Itemspresenter.
Question
Does anyone know how to solve this? Or perhaps knows a different approach to achieve the same result?
The problem here is the Content of the TreeViewItem gets wrapped in an implicit TreeViewItem by itself which thus gets another "footer" thus making it look like 2 "footer" elements per TreeViewItem.
Confirmed with Snoop:
The TreeViewItem we actually add
and the implicit one created by the Content of TreeViewItem
Work-around:
just apply a name to the "footer" TextBlock such as
<TextBlock x:Name="footer"
Grid.Row="2"
Grid.Column="1"
Text="Footer Text" />
and update the Trigger for HasItems -> False to:
<Trigger Property="HasItems"
Value="false">
<Setter TargetName="Expander"
Property="Visibility"
Value="Hidden" />
<Setter TargetName="footer"
Property="Visibility"
Value="Collapsed" />
</Trigger>
Now the footer text will only be visible when the TreeViewItem has children thereby giving you the appearance your expecting
How to insert checkbox to the left of the treeviewitem (expander), so it was the same item.
Sergo, Here is a version using the Control Template and we have Checkboxes being placed in column 0 of the item. They should align to the left with the TreeViewItem to the right. The 'magic' piece is in the CheckboxTreeItem style where we add a WrapPanel and place it in Grid.Column='0'.
<Window
x:Class="TreeViewHeaderTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300">
<Window.Resources>
<SolidColorBrush
x:Key="GlyphBrush"
Color="#444" />
<Style
x:Key="ExpandCollapseToggleStyle"
TargetType="ToggleButton">
<Setter
Property="Focusable"
Value="False" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="ToggleButton">
<WrapPanel
Background="Transparent">
<Path
x:Name="ExpandPath"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="1,1,1,1"
Fill="{StaticResource GlyphBrush}"
Data="M 4 0 L 8 4 L 4 8 Z" />
</WrapPanel>
<ControlTemplate.Triggers>
<Trigger
Property="IsChecked"
Value="True">
<Setter
Property="Data"
TargetName="ExpandPath"
Value="M 0 4 L 8 4 L 4 8 Z" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="TreeViewItemFocusVisual">
<Setter
Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border>
<Rectangle
Margin="0,0,0,0"
StrokeThickness="5"
Stroke="Black"
StrokeDashArray="1 2"
Opacity="0" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="CheckboxTreeItem"
TargetType="{x:Type TreeViewItem}">
<Setter
Property="IsExpanded"
Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter
Property="IsSelected"
Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter
Property="Background"
Value="Transparent" />
<Setter
Property="HorizontalContentAlignment"
Value="{Binding Path=HorizontalContentAlignment,
RelativeSource={RelativeSource
AncestorType={x:Type ItemsControl}}}" />
<Setter
Property="VerticalContentAlignment"
Value="{Binding Path=VerticalContentAlignment,
RelativeSource={RelativeSource
AncestorType={x:Type ItemsControl}}}" />
<Setter
Property="Padding"
Value="1,0,0,0" />
<Setter
Property="Foreground"
Value="{StaticResource {x:Static
SystemColors.ControlTextBrushKey}}" />
<Setter
Property="FocusVisualStyle"
Value="{StaticResource TreeViewItemFocusVisual}" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition
MinWidth="19"
Width="Auto" />
<ColumnDefinition
Width="Auto" />
<ColumnDefinition
Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition
Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<WrapPanel
Grid.Column='0'>
<CheckBox />
<ToggleButton
x:Name="Expander"
Style="{StaticResource
ExpandCollapseToggleStyle}"
IsChecked="{Binding Path=IsExpanded,
RelativeSource={RelativeSource
TemplatedParent}}"
ClickMode="Press" />
</WrapPanel>
<Border
Name="Bd"
Grid.Column="1"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding
BorderThickness}"
Padding="{TemplateBinding Padding}">
<ContentPresenter
x:Name="PART_Header"
ContentSource="Header"
HorizontalAlignment="{TemplateBinding
HorizontalContentAlignment}" />
</Border>
<ItemsPresenter
x:Name="ItemsHost"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2" />
</Grid>
<ControlTemplate.Triggers>
<Trigger
Property="IsExpanded"
Value="false">
<Setter
TargetName="ItemsHost"
Property="Visibility"
Value="Collapsed" />
</Trigger>
<Trigger
Property="HasItems"
Value="false">
<Setter
TargetName="Expander"
Property="Visibility"
Value="Hidden" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition
Property="HasHeader"
Value="false" />
<Condition
Property="Width"
Value="Auto" />
</MultiTrigger.Conditions>
<Setter
TargetName="PART_Header"
Property="MinWidth"
Value="75" />
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition
Property="HasHeader"
Value="false" />
<Condition
Property="Height"
Value="Auto" />
</MultiTrigger.Conditions>
<Setter
TargetName="PART_Header"
Property="MinHeight"
Value="19" />
</MultiTrigger>
<Trigger
Property="IsSelected"
Value="true">
<Setter
TargetName="Bd"
Property="Background"
Value="AliceBlue" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition
Property="IsSelected"
Value="true" />
<Condition
Property="IsSelectionActive"
Value="false" />
</MultiTrigger.Conditions>
<Setter
TargetName="Bd"
Property="Background"
Value="{StaticResource {x:Static
SystemColors.ControlBrushKey}}" />
<Setter
Property="Foreground"
Value="{StaticResource {x:Static
SystemColors.ControlTextBrushKey}}" />
</MultiTrigger>
<Trigger
Property="IsEnabled"
Value="false">
<Setter
Property="Foreground"
Value="{StaticResource {x:Static
SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<TreeView>
<TreeViewItem
Style='{StaticResource CheckboxTreeItem}'
Header='Item'
IsExpanded='True'>
<TreeViewItem
Style='{StaticResource CheckboxTreeItem}'
Header='SubItem 1' />
<TreeViewItem
Style='{StaticResource CheckboxTreeItem}'
Header='SubItem 2'>
<TreeViewItem
Style='{StaticResource CheckboxTreeItem}'
Header='SubItem a' />
<TreeViewItem
Style='{StaticResource CheckboxTreeItem}'
Header='SubItem b' />
</TreeViewItem>
</TreeViewItem>
</TreeView>
</Window>
You can modify the header of your TreeViewItem to add a Checkbox to the left. Here's a quick example to get you started, this xaml just adds a checkbox to the left and a TextBlock to the right.
<TreeView>
<TreeViewItem>
<TreeViewItem.Header>
<WrapPanel>
<CheckBox />
<TextBlock
Margin='5,0'
Text='Item' />
</WrapPanel>
</TreeViewItem.Header>
<TreeViewItem>
<TreeViewItem.Header>
<WrapPanel>
<CheckBox />
<TextBlock
Margin='5,0'
Text='SubItem' />
</WrapPanel>
</TreeViewItem.Header>
</TreeViewItem>
</TreeViewItem>
</TreeView>
Depending on your scenario you may want to create a whole new template to override the default look for all TreeViewItems, if you do, then checkout the MSDN TreeViewItem Control Template example:
http://msdn.microsoft.com/en-us/library/ms788727.aspx