When using a Popup inside a TreeView in WPF I am running into an issue where the controls inside the popup become unusable. For example, using the following code the ToggleButton inside the popup can only be toggled once and then becomes unable to be toggled back. Is there any way to work around this issue?
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TreeView>
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel>
<ToggleButton>
Button outside popup
</ToggleButton>
<Popup IsOpen="True">
<ToggleButton>
Button inside popup
</ToggleButton>
</Popup>
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</TreeView>
</Grid>
</Page>
The problem is that you are embedding the Popup inside the TreeViewItem, and somehow that is interfering with its built-in functionality. I don't think Popups are meant to be used that way, anyway. Because you can specify the PlacementTarget of a Popup, you can declare them anywhere and then open them at the location you want. The following mark-up demonstrates this with your example:
<StackPanel>
<Popup IsOpen="True" PlacementTarget="{Binding ElementName=buttonPanel}"
Placement="Bottom">
<ToggleButton>
Button inside popup
</ToggleButton>
</Popup>
<TreeView>
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel Name="buttonPanel">
<ToggleButton>
Button outside popup
</ToggleButton>
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</TreeView>
</StackPanel>
As you can see, the Popup can be declared anywhere. You can then use PlacementTarget to put it right where you want. With this change, the ToggleButton works as expected.
Thanks to Charlie finding the issue with using TreeView...
Setting Focusable on the tree view to false also seems to work. But may cause you other issues.
<TreeView Focusable="False">
From what I can tell the issue is which control is taking focus, so it looks like your treeview is taking focus of the mouse click instead of the button.
After discussion with the WPF team I found out that is this is just an issue with WPF.
For my case I was trying to create a drop dialog that is used for each TreeViewItem. I played around with different controls trying to get the looked I needed and I discovered that the Popup portion of a ComboBox worked fine inside a TreeView.
Because of this I ended up using a ComboBox inside the TreeView and forcing the ComboBox to only have one item that is always selected and that item would be my drop dialog. After this I just needed to style the ComboBox to match the look I needed. The code below shows the general idea of what I did.
<TreeView>
<TreeViewItem>
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top">
<ComboBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
</ComboBox.Resources>
<ComboBoxItem IsSelected="True">
<StackPanel Orientation="Vertical">
<Label>Some stuff on the combobox popup</Label>
<RadioButton>Radio Button 1</RadioButton>
<RadioButton>Radio Button 2</RadioButton>
<CheckBox>Check Box</CheckBox>
<Button HorizontalAlignment="Right">Ok</Button>
</StackPanel>
</ComboBoxItem>
</ComboBox>
</TreeViewItem>
</TreeView>
Well I had the same problem where a treeview shows hierarchical items using data template and multiple user control and one of the user control is a toggle button with a pop up in it.
This would freeze totally and would not respond at all. The problem is related to Focus property but setting Focusable to false does not always work.
By looking at the solutions provided above I liked the last one that uses combo box inside a treeviewitem. But it lead to one more problem. Whenever user select the (single) item of the combobox, it would appear in the combobox as a selectedValue and I just want to behave like a toggle with pop up.
Also I wanted to change the triangle on the combobox to ellipsis. So I tried this solution by changing the control template.
Here is my solution:
...
...
<Style x:Key="ComboBoxStyle1" TargetType="{x:Type ComboBox}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ComboBoxFocusVisual}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Padding" Value="4,3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid x:Name="MainGrid" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Popup x:Name="PART_Popup" Margin="1"
AllowsTransparency="true"
IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
Placement="Bottom"
PopupAnimation="Fade">
<Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}" Color="Transparent">
<Border x:Name="DropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="2" CornerRadius="0,4,4,4">
<ScrollViewer CanContentScroll="true">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.DirectionalNavigation="Contained"/>
</ScrollViewer>
</Border>
</Microsoft_Windows_Themes:SystemDropShadowChrome>
</Popup>
<ToggleButton Style="{StaticResource ComboBoxReadonlyToggleButton}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
<Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
<Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter Property="Background" Value="#FFF4F4F4"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEditable" Value="true">
<Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Padding" Value="3"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="ComboBoxItemStyle1" TargetType="{x:Type ComboBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Padding" Value="3,0,3,0"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<TreeView >
<TreeViewItem IsExpanded="True">
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top"
IsEditable="False"
Style="{StaticResource ComboBoxStyle1}">
<ComboBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
</ComboBox.Resources>
<ComboBoxItem IsSelected="False">
<StackPanel Orientation="Vertical">
<Label>Some stuff on the combobox popup</Label>
<RadioButton>Radio Button 1</RadioButton>
<RadioButton>Radio Button 2</RadioButton>
<CheckBox>Check Box</CheckBox>
<Button HorizontalAlignment="Right">Ok</Button>
</StackPanel>
</ComboBoxItem>
</ComboBox>
</TreeViewItem>
</TreeView>
Related
I've recently taken to learning WPF for a project. I've been styling a TabControl to fit the colors of a component library I'm using, but these strange white lines have appeared beside each TabItem, but only between items or before the first item.
What are they, and how can I get rid of them? I tried using the inspector provided in Visual Studio but they aren't selectable, which leads me to believe they are some internal part of TabItem, but I'm stuck at this point.
Usage:
<TabControl Grid.Row="1"
TabStripPlacement="Bottom"
BorderBrush="#00000000"
BorderThickness="0"
Resources="{StaticResource TabControlResources}">
<TabItem Header="Story">
<local:Workspace />
</TabItem>
<TabItem Header="Test">
Test Tab
</TabItem>
<TabItem Header="Test">
Test Tab 2
</TabItem>
</TabControl>
And style definition:
<ResourceDictionary x:Key="TabControlResources">
<Style TargetType="TabControl">
<Setter Property="Background"
Value="{StaticResource Fluent.Ribbon.Brushes.RibbonTabControl.Background}"/>
<Setter Property="Foreground"
Value="{StaticResource Fluent.Ribbon.Brushes.IdealForegroundColorBrush}" />
</Style>
<Style TargetType="TabItem">
<Setter Property="Foreground"
Value="{StaticResource Fluent.Ribbon.Brushes.IdealForegroundColorBrush}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background"
Value="{StaticResource Fluent.Ribbon.Brushes.RibbonTabControl.Background}" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background"
Value="{StaticResource Fluent.Ribbon.Brushes.RibbonTabItem.Active.Background}" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
Those are part of the TabItem. You can add the setter in the tab item style within your resource which should do the job:
<Style TargetType="{x:Type TabItem}">
<Setter Property="BorderBrush" Value="Red"/>
</Style>
And the result will be such:
Alternatively:
You can completely remove it, but unfortunately it is part of the template and the template has to be modified:
In Visual studio designer right click on one of the tab items and go to "Edit template" then "Edit a copy".
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
<Border x:Name="mainBorder" BorderBrush="Red" BorderThickness="0" Background="{TemplateBinding Background}" Margin="0">
<Border x:Name="innerBorder" BorderBrush="{StaticResource TabItem.Selected.Border}" BorderThickness="0" Background="{StaticResource TabItem.Selected.Background}" Margin="-1" Opacity="0"/>
</Border>
<ContentPresenter x:Name="contentPresenter" ContentSource="Header" Focusable="False" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
</Grid>
In there you have to modify the BorderThichness of mainBorder and innerBoarder to BorderThickness="0"
Result:
I have a ListBox with ItemsSource binding to an ObservableCollection<Item>.
Item has two string properties Name and Description.
DataTemplate for Item is StackPanel with Children: TextBlock with Text Bind to Name, TextBox with Text bind to Description.
What I have now:
1. When cursor is in TextBox corresponding to Description of an item, the corresponding ListBoxItem is highlighted.
2. I can use Tab to navigate among item's Textbox
3. If I move cursor to another named TextBox(theTextBox in code below) outside of listbox, the selected item do not highlight any more. That is my problem.
The png at https://drive.google.com/file/d/1tyxaBLnnjFUCJRTsHbwBwSvdU_X_L1fn/view?usp=sharing help explains my problem.
<DockPanel>
<ListBox ItemsSource="{Binding Items}" DockPanel.Dock="Top" Height="100" KeyboardNavigation.TabNavigation="Cycle">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Focusable" Value="False"/>
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="Background" Value="LightGreen" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<ItemContainerTemplate >
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}"/>
<TextBox Text="{Binding Description}"/>
</StackPanel>
</ItemContainerTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Name-"theTextBox" AcceptsReturn="True" />
</DockPanel>
The background when not focussed is different because it uses a different brush.
If this is something you want to apply to everything and you don't care whether they're focussed or not then you could over-ride the system colour.
In a resource dictionary merged by app.xaml add:
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color={x:Static SystemColors.HighlightColor}"/>
This is the style that I use globally for ListBoxItems that includes keeping the selected item highlighted even when the control loses focus.
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<!-- Revert to the "Windows 7" style template that used "SystemColors.HighlightBrushKey" etc -->
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border
x:Name="ItemBorder"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<!-- Use the same colours for selected items, whether or not the control has focus -->
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="ItemBorder" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I had a WPF menu which I'd styled using control templates. Then the client wanted to use images instead of text for the Top Level navigation items.
No problem, I created a control template for each top-level item and set my Template attribute on each MenuItem to match the custom template like the one below. I've a Trigger that changes the image on rollover.
My problem is that when you click on the Menu Item that should have a sub-menu items that they no longer drop-down.
The commands fire for the Top-level items that don't have children. And as soon as I remove my code specifying the template from my Menu Item with children I see the text version with the drop-down.
What do I need to do to keep my image-based top-level menu item and keep my drop-downs?
Thanks in advance.
<Menu Grid.Row="0" Grid.Column="0" Name="uxMenu" Margin="0 2 0 0">
<MenuItem Header="Home" Name="uxHome" Command="cmds:NavigationCommands.HomeViewNavigationCommand" Template="{DynamicResource HomeButtonTemplate}"/>
<MenuItem Header="Admin" Name="uxAdmin" Template="{DynamicResource MenuExitButtonTemplate}">
<MenuItem Header="_Setup">
<MenuItem Header="_Overview" Command="cmds:NavigationCommands.MenuAdminSetupOverviewNavigationCommand"/>
<MenuItem Header="_Cameras" Command="cmds:NavigationCommands.MenuAdminSetupCameraNavigationCommand" />
</MenuItem>
</MenuItem>
</Menu>
<ControlTemplate x:Key="HomeButtonTemplate" TargetType="{x:Type MenuItem}">
<Grid >
<Image x:Name="myimage" Source="/Images/Navigation/home_off.png" Width="100" Height="52" />
</Grid>
<ControlTemplate.Triggers >
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter TargetName="myimage" Property="Source" Value="/Images/Navigation/home_on.png" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
In response to H.B's post...
I do have a big ol' set of control templates that I'm currently using to style my menu. So if I want to specify a different control template for each of my top level headers I'm going to have to have an entirely new set of control templates for each one?
I'm unsure of the exact syntax to use, especially for the x:Key and TargetType attributes.
For example. My current code looks like this for my TopLevelHeader and SubmenuHeader control templates. (Copied from the 'menutemplatingpage' you reference')
<!-- TopLevelHeader (children)-->
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelHeaderTemplateKey}" TargetType="MenuItem">
<Border Name="Border">
<Grid>
<ContentPresenter Margin="0 24 0 14" ContentSource="Header" RecognizesAccessKey="True" />
<Popup
Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsSubmenuOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Fade">
<Border
Name="SubmenuBorder"
SnapsToDevicePixels="True"
Background="{StaticResource WindowBackgroundBrush}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1" >
<StackPanel
IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Cycle" />
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSuspendingPopupAnimation" Value="true">
<Setter TargetName="Popup" Property="PopupAnimation" Value="None"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="false">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter TargetName="Border" Property="Background" Value="Transparent"/>
<Setter TargetName="Border" Property="BorderBrush" Value="Transparent"/>
<Setter TargetName="Border" Property="BorderThickness" Value="0"/>
<Setter Property="Foreground" Value="#fff"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="true">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter TargetName="Border" Property="Background" Value="Transparent"/>
<Setter TargetName="Border" Property="BorderBrush" Value="Transparent"/>
<Setter TargetName="Border" Property="BorderThickness" Value="0"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="True">
<Setter TargetName="SubmenuBorder" Property="CornerRadius" Value="0,0,4,4"/>
<Setter TargetName="SubmenuBorder" Property="Padding" Value="10"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- SubmenuHeader -->
<ControlTemplate x:Key="{x:Static MenuItem.SubmenuHeaderTemplateKey}" TargetType="MenuItem">
<Border Name="Border" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Icon"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Shortcut"/>
<ColumnDefinition Width="13"/>
</Grid.ColumnDefinitions>
<ContentPresenter
Name="Icon"
Margin="6,0,6,0"
VerticalAlignment="Center"
ContentSource="Icon"/>
<ContentPresenter
Name="HeaderHost"
Grid.Column="1"
ContentSource="Header"
RecognizesAccessKey="True"/>
<TextBlock x:Name="InputGestureText"
Grid.Column="2"
Text="{TemplateBinding InputGestureText}"
Margin="5,2,2,2"
DockPanel.Dock="Right"/>
<Path
Grid.Column="3"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 0 7 L 4 3.5 Z"
Fill="{StaticResource GlyphBrush}" />
<Popup
Name="Popup"
Placement="Right"
HorizontalOffset="-4"
IsOpen="{TemplateBinding IsSubmenuOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Fade">
<Border
Name="SubmenuBorder"
SnapsToDevicePixels="True"
Background="{StaticResource WindowBackgroundBrush}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1" >
<StackPanel
IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Cycle" />
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Icon" Value="{x:Null}">
<Setter TargetName="Icon" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource SelectedBackgroundBrush}"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="True">
<Setter TargetName="SubmenuBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="SubmenuBorder" Property="Padding" Value="0,3,0,3"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
So if I add my new Control template with the key of "HomeButtonTemplate" as shown near the top of my post I'm going to have to add a new section (as well as all the other ControlTemplates for things like SubmenuItem etc.
How do these new ControlTemplates know that they belong to the same group of control templates? I feel I'm not asking this correctly.
Thanks for any advice you can give.
You completely remove the existing template (which is fairly complex) by specifying your own, your template no longer provides the necessary functionality. There is a part in the control template indentified with the name PART_Popup, which is used to display sub-items.
Check this page for a link (Default WPF themes) where you can download the default styles which include the templates to see what your template should look like.
Also have a look at the menu templating page which should give you an idea just how complex templating the menu is.
This might be a bit late but I recently had the same issue.
What worked for me was to create a StackPanel like so
<StackPanel ClipToBounds="True"
Orientation="Horizontal"
IsItemsHost="True" />
inside the Border which is inside the ControlTemplate.
Leaving you with something along the lines of this.
<ControlTemplate TargetType="Menu">
<Border Background="{TemplateBinding Background}"
BorderBrush="#252525"
BorderThickness="1"
CornerRadius="5">
<StackPanel ClipToBounds="True"
Orientation="Horizontal"
IsItemsHost="True" />
</Border>
</ControlTemplate>
just watch this screenshot I made so you see the difference:
I have these requirments to be changed in the ComboBox`s PopUp so it looks like the grouped WPF DataGrid, its only about the Popup-area, do not judge the editable area of the ComboBox or that there is no Header... Important are these things, because I could not change them:
ComboBox:
(Green Line) The alternating
Background of the Item must start at
the beginning
(Red Line) The TextBlocks within the
Border must be aligned Center OR
Right1.
(Blue) The weakly visible horizontal
Border must always stretch to the
right side or take all space2.
to 1.) I have no idea why there is a margin
to 2.) HorizontalAlignment of the TextBlock does not work
to 3.) I can make the stackpanel in the ItemTemplate of the Combobox a read background then you can see very well the red color has a margin somehow on the right and left side. Have no idea how to remove that.
Anyone can help, please?
If you want to see the textbox live just download it here:
http://www.sendspace.com/file/6lmbrh
Its a 30 kb VS2010 .NET 4.0 project.
Here is the XAML for the ComboBox:
<Window x:Class="TestComboGrouped.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="200">
<Window.Resources>
<Style x:Key="ComboBoxItemStyle" TargetType="ComboBoxItem">
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<Trigger Property="ComboBox.AlternationIndex" Value="0">
<Setter Property="Background" Value="White"></Setter>
</Trigger>
<Trigger Property="ComboBox.AlternationIndex" Value="1">
<Setter Property="Background" >
<Setter.Value>
<LinearGradientBrush RenderOptions.EdgeMode="Aliased" StartPoint="0.5,0.0" EndPoint="0.5,1.0">
<GradientStop Color="#FFFEFEFF" Offset="0"/>
<GradientStop Color="#FFE4F0FC" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="ComboBoxBorderStyle" TargetType="Border">
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="BorderBrush" Value="#FFCEDFF6" />
<Setter Property="BorderThickness" Value="1 0 0 1" />
</Style>
<Style x:Key="ComboBoxStyle" BasedOn="{StaticResource {x:Type ComboBox}}" TargetType="{x:Type ComboBox}">
<Setter Property="ItemContainerStyle" Value="{StaticResource ComboBoxItemStyle}"/>
</Style>
<!-- Grouped CollectionView -->
<CollectionViewSource Source="{Binding WeeklyDateList,IsAsync=False}" x:Key="WeeklyView">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="MonthName"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<StackPanel>
<ComboBox
ItemsSource="{Binding Source={StaticResource ResourceKey=WeeklyView}}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
Style="{StaticResource ComboBoxStyle}"
AlternationCount="2"
MaxDropDownHeight="300"
Width="Auto"
x:Name="comboBox"
>
<ComboBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock
Padding="5,0,0,0"
Background="White"
Foreground="DarkBlue"
FontSize="14"
FontWeight="DemiBold"
Text="{Binding Name}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Border Style="{StaticResource ComboBoxBorderStyle}">
<TextBlock Width="100" Foreground="Purple" Text="{Binding WeeklyLessonDate, StringFormat='yyyy-MM-dd'}"/>
</Border>
<Border Style="{StaticResource ComboBoxBorderStyle}">
<TextBlock Padding="5,0,5,0" Width="40" Text="{Binding WeekNumber}"/>
</Border>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Window>1.2.
UPDATE:
#Meleak thats the updated image it looks very nice thanks to you:
I was just about to put my old 2-"ColumnHeader" in that ComboBox`s Popup top area but I could not find anymore my sample... seems due to changing/trying a lot I have overritten that code :/ I know I did it in the controltemplate above the scrollviewer with a stackpanel or a grid with 2 rowdefinitions. But your code looks now totally different to my default combobox controltemplate I have no idea how to merge both code snippets.
I think that was the code where I put the 2 "column headers", just search for inside the POPUP
<Style x:Key="ComboBoxStyle1" TargetType="{x:Type ComboBox}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ComboBoxFocusVisual}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Padding" Value="4,3"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid x:Name="MainGrid" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
</Grid.ColumnDefinitions>
<Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
<Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}">
<Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
// Here should be the column headers, but how merge your code with the ItemsPresenter?
<ScrollViewer x:Name="DropDownScrollViewer">
<Grid RenderOptions.ClearTypeHint="Enabled">
<Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" Height="{Binding ActualHeight, ElementName=DropDownBorder}" Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
</Canvas>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ScrollViewer>
</Border>
</Microsoft_Windows_Themes:SystemDropShadowChrome>
</Popup>
<ToggleButton BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ComboBoxReadonlyToggleButton}"/>
<ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
<Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
<Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter Property="Background" Value="#FFF4F4F4"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger Property="ScrollViewer.CanContentScroll" SourceName="DropDownScrollViewer" Value="false">
<Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
<Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEditable" Value="true">
<Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="Template" Value="{StaticResource ComboBoxEditableTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
I think it looks pretty close. You can download my modified version from here
Added a template for ComboBoxItem
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<Style x:Key="ComboBoxItemStyle" TargetType="ComboBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Grid HorizontalAlignment="Stretch"
Margin="-5,0,0,0"
Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="45"/>
</Grid.ColumnDefinitions>
<Border Name="border1"
BorderThickness="0,0,1,1"
BorderBrush="#FFCEDFF6"
Grid.Column="0">
<TextBlock Foreground="Purple"
HorizontalAlignment="Right"
Margin="0,0,2,0"
Text="{Binding WeeklyLessonDate, StringFormat='yyyy-MM-dd'}"/>
</Border>
<Border Name="border2"
BorderThickness="0,0,1,1"
BorderBrush="#FFCEDFF6"
Grid.Column="1">
<TextBlock HorizontalAlignment="Center"
Text="{Binding WeekNumber}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter TargetName="border1" Property="Background" Value="{StaticResource SelectedBackgroundBrush}"/>
<Setter TargetName="border2" Property="Background" Value="{StaticResource SelectedBackgroundBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<Trigger Property="ComboBox.AlternationIndex" Value="0">
<Setter Property="Background" Value="White"></Setter>
</Trigger>
<Trigger Property="ComboBox.AlternationIndex" Value="1">
<Setter Property="Background" >
<Setter.Value>
<LinearGradientBrush RenderOptions.EdgeMode="Aliased" StartPoint="0.5,0.0" EndPoint="0.5,1.0">
<GradientStop Color="#FFFEFEFF" Offset="0"/>
<GradientStop Color="#FFE4F0FC" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Ok in my ListBox scrolling images w/ text, etc. the saga continues. When I click one of the items, to select it, that runs a process to open a web browser and go to a specific URL. The problem I'm having now is that when the WPF app loses focus, and the web browser opens, the item clicked inside the listbox turns white. Here's the whole ListBox XAML. I have set the selected items to transparent, so does this have something to do with the WPF app losing focus?
Is there something I can add tom the code that runs the process to open the web browser to set focus back to the WPF app?
Thanks.
<ListBox ItemsSource="{Binding Source={StaticResource WPFApparelCollection}}" Margin="61,-8,68,-18" ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Hidden" SelectionMode="Single" x:Name="list1" MouseLeave="List1_MouseLeave" MouseMove="List1_MouseMove" Style="{DynamicResource ListBoxStyle1}" Background="Transparent" BorderThickness="0">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<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="20,10,20,10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd" SnapsToDevicePixels="true" Background="Transparent" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true" />
<Condition Property="Selector.IsSelectionActive" Value="false" />
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" 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>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Grid>
<Image Source="{Binding Image}" MouseLeave="Image_MouseLeave" MouseEnter="Image_MouseEnter" Cursor="Hand" Tag="{Binding Link}" MouseLeftButtonDown="Image_MouseLeftButtonDown" VerticalAlignment="Top" HorizontalAlignment="Left"></Image>
</Grid>
<Label Content="{Binding Name}" Cursor="Hand" Tag="{Binding Link}" MouseLeftButtonDown="Label_MouseLeftButtonDown" VerticalAlignment="Bottom" Foreground="White" Style="{StaticResource Gotham-Medium}" FontSize="8pt" HorizontalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
One trick I've found when playing with selection colours in a ListBox is to work with the system brushes rather than fighting against them.
When a ListBox is focused and an item is selected, that item's background is SystemColors.HighlightBrush. When the ListBox loses focus, however, the selected item's background becomes SystemColors.ControlBrush.
Knowing this, you can override the system brushes for that ListBox so that the items within are painted with the colours you want.
<ListBox>
<ListBox.Resources>
<!-- override the system brushes so that selected items are transparent
whether the ListBox has focus or not -->
<SolidColorBrush
x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent" />
<SolidColorBrush
x:Key="{x:Static SystemColors.ControlBrushKey}"
Color="Transparent" />
<SolidColorBrush
x:Key="{x:Static SystemColors.HighlightTextBrushKey}"
Color="Black" />
</ListBox.Resources>
<!-- ... your items here ... -->
</ListBox>