I'm currently trying to implement my own stylized ComboBox in WPF. Everything is working fine, except for the scrollviewer. Simply put, the vertical scroll bar does nothing. Here is an image:
As you can see, the vertical scrollbar is scrolled all the way down, but it did not seem to trigger the effect of actually scrolling. I have 12 dummy items in the Combobox. I was reading online that the ScrollViewer style requires three things to work: ScrollContentPresenter, VerticalScrollBar, and HorizontalScrollBar. I have all three declared in my scrollviewer style, which is as follows:
<Style x:Key="VoidwalkerDarkScrollviewer" TargetType="{x:Type ScrollViewer}">
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="VerticalScrollBarVisibility" Value="Visible" />
<Setter Property="Padding" Value="4" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0" Color="#FFA3AEB9" />
<GradientStop Offset="0.375" Color="#FF8399A9" />
<GradientStop Offset="0.375" Color="#FF718597" />
<GradientStop Offset="1" Color="#FF617584" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollViewer">
<Border
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="2">
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ScrollContentPresenter
x:Name="ScrollContentPresenter"
Margin="{TemplateBinding Padding}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}" />
<Rectangle
Grid.Row="1"
Grid.Column="1"
Fill="#FFE9EEF4" />
<ScrollBar
x:Name="VerticalScrollBar"
Grid.Row="0"
Grid.Column="1"
Width="18"
Margin="0,-1,-1,-1"
Background="Red"
IsTabStop="False"
Maximum="{TemplateBinding ScrollableHeight}"
Minimum="0"
Orientation="Vertical"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Value="{TemplateBinding VerticalOffset}" />
<ScrollBar
x:Name="HorizontalScrollBar"
Grid.Row="1"
Grid.Column="0"
Height="18"
Margin="-1,0,-1,-1"
IsTabStop="False"
Maximum="{TemplateBinding ScrollableWidth}"
Minimum="0"
Orientation="Horizontal"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Value="{TemplateBinding HorizontalOffset}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And here is my Combobox style (Omitting extras which are not relevant)
<Style x:Key="VoidwalkerDarkComboBox" TargetType="{x:Type ComboBox}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="MinWidth" Value="120" />
<Setter Property="MinHeight" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton
Name="ToggleButton"
Grid.Column="2"
ClickMode="Press"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
Template="{StaticResource ComboBoxToggleButton}" />
<ContentPresenter
Name="ContentSite"
Margin="3,3,23,3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
IsHitTestVisible="False" />
<TextBox
x:Name="PART_EditableTextBox"
Margin="3,3,23,3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Background="Transparent"
Focusable="True"
Foreground="#d0d0d0"
IsReadOnly="{TemplateBinding IsReadOnly}"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
Text="{TemplateBinding Text}"
Visibility="Visible" />
<Popup
Name="Popup"
AllowsTransparency="True"
Focusable="False"
IsOpen="{TemplateBinding IsDropDownOpen}"
Placement="Bottom"
PopupAnimation="Slide">
<Grid
Name="DropDown"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
SnapsToDevicePixels="True">
<Border
x:Name="DropDownBorder"
Background="#1b1b1c"
BorderBrush="#3f3f46"
BorderThickness="1" />
<ScrollViewer
Margin="4,6,4,6"
SnapsToDevicePixels="True"
Style="{DynamicResource VoidwalkerDarkScrollviewer}"><!-- IF I REMOVE THIS STYLE EVERYTHING WORKS FINE !-->
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="LightGray" />
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false" />
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="0,0,4,4" />
<Setter TargetName="DropDownBorder" Property="Margin" Value="0" />
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false" />
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible" />
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
As the comment in the style suggests, everything works fine if I simply remove the ScrollViewer style from the combobox...but I need it to complete my dark theme.
Does anyone know what I am missing to make this work?
rewriting ScrollViewer template to change ScrollBar color is an overkill.
ScrollBar is a part of ScrollViewer which is a part of ComboBox. Add a default ScrollBar style in ComboBox style Resources and change color via setter:
<Style TargetType="ComboBox">
<Style.Resources>
<Style TargetType="ScrollBar">
<Setter Property="Background" Value="Red"/>
</Style>
</Style.Resources>
</Style>
I figured it out. Just needed to dig a little deeper online. Here's some working XAML(Some of it may not be needed, but it's for full combobox styling) and a picture to show it)
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
Grid.ColumnSpan="2"
Background="#3f3f46"
BorderBrush="#3f3f46"
BorderThickness="1" />
<Border
Grid.Column="0"
Margin="1"
Background="#333337"
BorderBrush="#3f3f46"
BorderThickness="0,0,1,0" />
<Path
x:Name="Arrow"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"
Fill="#d0d0d0" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="LightGray" />
<Setter TargetName="Border" Property="BorderBrush" Value="Gray" />
<Setter Property="Foreground" Value="DarkGray" />
<Setter TargetName="Arrow" Property="Fill" Value="DarkGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="{x:Type TextBox}">
<ScrollViewer
x:Name="PART_ContentHost"
Background="{TemplateBinding Background}"
Focusable="False" />
</ControlTemplate>
<ControlTemplate x:Key="ScrollBackground" TargetType="RepeatButton">
<Border Background="Transparent" />
</ControlTemplate>
<Style x:Key="ScrollThumbStyle" TargetType="Thumb">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Rectangle
Width="13"
Fill="#7D7D7D"
RadiusX="5"
RadiusY="5" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ComboBox style -->
<Style x:Key="VoidwalkerDarkComboBox" TargetType="{x:Type ComboBox}">
<Style.Resources>
<Style TargetType="ScrollBar">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollBar">
<Grid Width="15">
<Border
Width="13"
HorizontalAlignment="Center"
Background="#33555555"
CornerRadius="5" />
<Track
Name="PART_Track"
Width="{TemplateBinding Width}"
HorizontalAlignment="Center"
IsDirectionReversed="true"
Maximum="{TemplateBinding Maximum}"
Minimum="{TemplateBinding Minimum}"
Value="{TemplateBinding Value}">
<Track.DecreaseRepeatButton>
<RepeatButton Command="ScrollBar.LineUpCommand" Template="{StaticResource ScrollBackground}" />
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="ScrollBar.LineDownCommand" Template="{StaticResource ScrollBackground}" />
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollThumbStyle}" />
</Track.Thumb>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="MinWidth" Value="120" />
<Setter Property="MinHeight" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton
Name="ToggleButton"
Grid.Column="2"
ClickMode="Press"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
Template="{StaticResource ComboBoxToggleButton}" />
<ContentPresenter
Name="ContentSite"
Margin="3,3,23,3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
IsHitTestVisible="False" />
<TextBox
x:Name="PART_EditableTextBox"
Margin="3,3,23,3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Background="Transparent"
Focusable="True"
Foreground="#d0d0d0"
IsReadOnly="{TemplateBinding IsReadOnly}"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
Text="{TemplateBinding Text}"
Visibility="Visible" />
<Popup
Name="Popup"
AllowsTransparency="True"
Focusable="False"
IsOpen="{TemplateBinding IsDropDownOpen}"
Placement="Bottom"
PopupAnimation="Slide">
<Grid
Name="DropDown"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
SnapsToDevicePixels="True">
<Border
x:Name="DropDownBorder"
Background="#1b1b1c"
BorderBrush="#3f3f46"
BorderThickness="1" />
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="LightGray" />
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false" />
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="0,0,4,4" />
<Setter TargetName="DropDownBorder" Property="Margin" Value="0" />
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false" />
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible" />
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My best guess is that originally overriding the ScrollViewer itself must have broke something internally...perhaps I left something out. I don't know. Either way, a solution/alternative is just to provide a style for the scrollbars themselves, and ignore the ScrollViewer altogether.
Related
I have a DataGrid and one of DataGridColumns is defined as:
<DataGridTemplateColumn Width=".2*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid Name="MyDMGrid">
<ComboBox Name="VersionCB1" ItemsSource="{Binding cbValues}" SelectedItem="{Binding cbSelectedItem}" IsHitTestVisible="True"
Style="{StaticResource ResourceKey=VersionCB}" SelectionChanged="VersionChange" MinWidth="20" MaxWidth="150"
HorizontalAlignment="Right" Margin="0,0,40,0" Foreground="Black" VerticalAlignment="Center" MouseEnter="VersionCB1_MouseEnter" />
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
VersionCB Resource is defined in app.xaml as:
<Style x:Key="VersionCB" TargetType="{x:Type ComboBox}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="MinWidth" Value="120" />
<Setter Property="MinHeight" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<ToggleButton x:Name="ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
Grid.Column="2"
Focusable="false"
ClickMode="Press"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}"/>
<ContentPresenter x:Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
TextElement.Foreground="#FFF3F3F3"
TextElement.FontFamily="SegoeUI"
TextElement.FontSize="14"
Margin="3,3,23,3"
VerticalAlignment="Stretch"
HorizontalAlignment="Left">
</ContentPresenter>
<TextBox x:Name="PART_EditableTextBox"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
BorderBrush="Transparent"
BorderThickness="0"
Margin="3,3,23,3"
Focusable="True"
Background="Transparent"
Visibility="Hidden"
IsReadOnly="{TemplateBinding IsReadOnly}" />
<Popup x:Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid x:Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder" BorderThickness="1">
<Border.BorderBrush>
<SolidColorBrush Color="Transparent" />
</Border.BorderBrush>
<Border.Background>
<SolidColorBrush Color="#FFEBEBEB" />
</Border.Background>
</Border>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95" />
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false" />
</Trigger>
<Trigger SourceName="Popup" Property="AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="0" />
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am seeing a border on combobox on mouse over as shown below:
I have tried following to get rid of the border. In VersionCB1_MouseEnter I wrote the following:
ComboBox cmb = e.OriginalSource as ComboBox;
cmb.BorderThickness = new Thickness(0, 0, 0, 0);
cmb.BorderBrush =System.Windows.Media.Brushes.Transparent;
But this does not work? How can I get rid of combo box border on Mouse Over?
I think the border you are seeing is from ComboBoxToggleButton template. I threw your code in a combo box to see if I could recreate the problem and I'm not seeing any border, but I had to remove the two references ComboBoxTextBox and ComboBoxToggleButton since I don't have them.
You could add the mouse over triggers to the toggle button control template to see if it is in control of that border. I'm pretty sure it does. I was able to control the mouse over border by adding the triggers. I did a simple template to estimate what you have. I was able to produce the desired behavior.
<ControlTemplate
x:Key="ComboBoxToggleButton"
TargetType="{x:Type ToggleButton}">
<Border
x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="true">
<ContentPresenter
x:Name="contentPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Focusable="False"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsDefaulted" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="Transparent" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter TargetName="border" Property="BorderBrush" Value="Black" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
While trying to style a ToggleButton with a Chevron shape, i cannot get rid of the annoying thin lines which are rendered, which can be seen at the screenshot.
Can anyone help out here?
Style:
<Style x:Key="ChevronButtonStyle" TargetType="{x:Type ToggleButton}" >
<Setter Property="Margin" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<StackPanel Orientation="Horizontal" Margin="0,0,-10,0" Height="30" ClipToBounds="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Path Grid.Column="0" Name="ChevronLeft" Data="M0,0 10,0 10,30 0,30 10,15" Fill="{TemplateBinding Background}"/>
<Grid Grid.Column="1" >
<Rectangle Name="ChevronBack" Fill="{TemplateBinding Background}" Margin="0,0,0,0"/>
<TextBlock Grid.Column="2" Name="ChevronText" Text="{TemplateBinding Content}" Margin="10,5" VerticalAlignment="Center" />
</Grid>
<Path Grid.Column="2" Name="ChevronRight" Data="M0,0 10,15 0,30" Fill="{TemplateBinding Background}" />
</Grid>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="ChevronLeft" Property="Fill" Value="{StaticResource Petrol}" />
<Setter TargetName="ChevronBack" Property="Fill" Value="{StaticResource Petrol}" />
<Setter TargetName="ChevronRight" Property="Fill" Value="{StaticResource Petrol}" />
<Setter TargetName="ChevronText" Property="Foreground" Value="White" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ChevronLeft" Property="Fill" Value="DarkGray" />
<Setter TargetName="ChevronBack" Property="Fill" Value="DarkGray" />
<Setter TargetName="ChevronRight" Property="Fill" Value="DarkGray" />
<Setter TargetName="ChevronText" Property="Foreground" Value="Black" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="ChevronText" Property="Foreground" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Theses artifacts should disappear when you set UseLayoutRounding or SnapsToDevicePixels on the parent Grid:
<Grid UseLayoutRounding="True">
Or
<Grid SnapsToDevicePixels="True">
I've been working on a custom combo box style based on the one here:
https://gist.github.com/HalidCisse/50df055a0c02714a9e3f
The problem I'm having is that the selected item text does not show up when I select an item or set some text to be shown by default. However if I set it so the combo box is editable I can see a blue outline the length of my text, where it should be. This makes me think the text is actually bound and being displayed, it's just invisible or hidden. Unfortunately I've been messing with this for a couple of hours and I've had no luck trying to unhide it.
What it looks like when something is selected
This is how I have combo box setup:
<ComboBox Style="{StaticResource ComboBoxFlatStyle}"
Height="40"
FontSize="16"
Margin="10 0 10 0"
IsEnabled="True"
IsEditable="True"
IsReadOnly="True"
Text="Testing Text">
<ComboBoxItem Content="Test 0"/>
<ComboBoxItem Content="Test 1"/>
</ComboBox>
This is what I have:
<SolidColorBrush x:Key="ComboBoxNormalBorderBrush"
Color="#333333" />
<SolidColorBrush x:Key="ComboBoxNormalBackgroundBrush"
Color="#222222" />
<SolidColorBrush x:Key="ComboBoxDisabledForegroundBrush"
Color="White" />
<SolidColorBrush x:Key="ComboBoxDisabledBackgroundBrush"
Color="#222222" />
<SolidColorBrush x:Key="ComboBoxDisabledBorderBrush"
Color="#333333" />
<SolidColorBrush x:Key="DropDownBackgroundBrush"
Color="#111111" />
<SolidColorBrush x:Key="DropDownTextFillBrush"
Color="#FFFFB83D" />
<SolidColorBrush x:Key="ArrowFillBrush"
Color="#FFFFB83D" />
<ControlTemplate x:Key="ComboBoxToggleButtonTemplate"
TargetType="ToggleButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Border Name="Border"
Grid.ColumnSpan="2"
Background="{StaticResource ComboBoxNormalBackgroundBrush}"
BorderBrush="{StaticResource ComboBoxNormalBorderBrush}"
BorderThickness="1, 1, 1, 1"
CornerRadius="0" />
<Border Name="ButtonBorder"
Grid.Column="1"
Margin="1, 1, 1, 1"
Background="{StaticResource ComboBoxNormalBackgroundBrush}"
BorderBrush="#444"
BorderThickness="0, 0, 0, 0"
CornerRadius="0, 0, 0, 0" />
<Path Name="Arrow"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z"
Fill="{StaticResource ArrowFillBrush}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter TargetName="ButtonBorder" Property="Panel.Background" Value="#111111" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter TargetName="Arrow" Property="Shape.Fill" Value="{StaticResource ArrowFillBrush}" />
<Setter TargetName="ButtonBorder" Property="Panel.Background" Value="#111111" />
</Trigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" Value="{StaticResource ComboBoxDisabledForegroundBrush}" />
<Setter TargetName="Arrow" Property="Shape.Fill" Value="#999" />
<Setter TargetName="Border" Property="Panel.Background" Value="{StaticResource ComboBoxDisabledBackgroundBrush}" />
<Setter TargetName="ButtonBorder" Property="Border.BorderBrush" Value="{StaticResource ComboBoxDisabledBorderBrush}" />
<Setter TargetName="ButtonBorder" Property="Panel.Background" Value="{StaticResource ComboBoxDisabledBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="ComboBoxFlatStyle"
TargetType="{x:Type ComboBox}">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<ControlTemplate.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="#222222" />
</ControlTemplate.Resources>
<Grid>
<ContentPresenter x:Name="ContentSite"
Margin="5, 3, 23, 3"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Content="{TemplateBinding ComboBox.SelectionBoxItem}"
ContentTemplate="{TemplateBinding ComboBox.SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
IsHitTestVisible="False" />
<TextBox Name="PART_EditableTextBox"
Margin="3, 3, 23, 3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Background="Transparent"
Focusable="True"
IsReadOnly="{TemplateBinding IsReadOnly}"
Visibility="Hidden">
<TextBox.Template>
<ControlTemplate TargetType="TextBox">
<Border x:Name="PART_ContentHost"
Focusable="False" />
</ControlTemplate>
</TextBox.Template>
</TextBox>
<!-- Popup showing items -->
<Popup Name="Popup"
AllowsTransparency="True"
Focusable="False"
IsOpen="{TemplateBinding ComboBox.IsDropDownOpen}"
Placement="Bottom"
PopupAnimation="Slide">
<Grid Name="DropDown"
MinWidth="{TemplateBinding FrameworkElement.ActualWidth}"
MaxHeight="{TemplateBinding ComboBox.MaxDropDownHeight}"
SnapsToDevicePixels="True">
<Border Name="DropDownBorder"
Margin="0, 1, 0, 0"
Background="{StaticResource DropDownBackgroundBrush}"
BorderBrush="{StaticResource ComboBoxNormalBorderBrush}"
BorderThickness="1,1,1,1"
CornerRadius="0" />
<ScrollViewer Margin="4"
SnapsToDevicePixels="True">
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
<ToggleButton Name="ToggleButton"
Grid.Column="2"
ClickMode="Press"
Focusable="False"
IsChecked="{Binding Path=IsDropDownOpen,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}"
Template="{StaticResource ComboBoxToggleButtonTemplate}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.HasItems" Value="False">
<Setter TargetName="DropDownBorder" Property="FrameworkElement.MinHeight" Value="95" />
</Trigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" Value="{StaticResource ComboBoxDisabledForegroundBrush}" />
</Trigger>
<Trigger Property="ItemsControl.IsGrouping" Value="True">
<Setter Property="ScrollViewer.CanContentScroll" Value="False" />
</Trigger>
<Trigger Property="ComboBox.IsEditable" Value="True">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter TargetName="ContentSite" Property="UIElement.Visibility" Value="Hidden" />
<Setter TargetName="PART_EditableTextBox" Property="UIElement.Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="FrameworkElement.FocusVisualStyle" Value="{x:Null}" />
<Setter Property="FrameworkElement.OverridesDefaultStyle" Value="True" />
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="TextElement.Foreground" Value="{StaticResource DropDownTextFillBrush}" />
<Setter Property="UIElement.SnapsToDevicePixels" Value="True" />
</Style>
Ok so the problem was the order of the items in the combo box. I have been using the XAML styler extension for vs2013 and this can automatically format your xaml to make it look nicer. However I had a setting on that orders my elements automatically which meant the elements were being placed onto a empty grid in the wrong order, this obscuring the text.
For reference the correct order is:
ToggleButton
ContentPresenter
TextBox
Popup
Focusable="true"
Make this false, and you will see the selected text appearing. I dont understand why it is so, I too had similar issue, and it worked went setting the Focusable="False"
At a TreeView, I have the following Resources to keep the item selected when Focus is lost.
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Resources>
<!-- SelectedItem with focus -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Opacity=".8"
Color="DodgerBlue" />
<!-- SelectedItem without focus -->
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
Opacity=".3"
Color="DodgerBlue" />
</Style.Resources>
</Style>
</TreeView.Resources>
But I also have a template in a resource dictionary that I use to get a FullRowSelect style. It is from LeeCampbells Article here: Horizontal stretch on TreeViewItems
<Style BasedOn="{StaticResource {x:Type TreeViewItem}}" TargetType="TreeViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="19" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!--
Note that the following do not work, but I believe the top 2 should?!
<ToggleButton IsChecked="{TemplateBinding IsExpanded}" ClickMode="Press" Name="Expander">
<ToggleButton IsChecked="{TemplateBinding Property=IsExpanded}" ClickMode="Press" Name="Expander">
<ToggleButton IsChecked="{TemplateBinding Path=IsExpanded}" ClickMode="Press" Name="Expander">
-->
<ToggleButton Name="Expander"
ClickMode="Press"
IsChecked="{Binding Path=IsExpanded,
RelativeSource={RelativeSource TemplatedParent}}">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="UIElement.Focusable" Value="false" />
<Setter Property="FrameworkElement.Width" Value="16" />
<Setter Property="FrameworkElement.Height" Value="16" />
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Width="16"
Height="16"
Background="#00FFFFFF"
Padding="5,5,5,5">
<Path Name="ExpandPath"
Fill="#00FFFFFF"
Stroke="#FF989898">
<Path.Data>
<PathGeometry Figures="M0,0L0,6L6,0z" />
</Path.Data>
<Path.RenderTransform>
<RotateTransform Angle="135" CenterX="3" CenterY="3" />
</Path.RenderTransform>
</Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter TargetName="ExpandPath" Property="Shape.Stroke" Value="#FF1BBBFA" />
<Setter TargetName="ExpandPath" Property="Shape.Fill" Value="#00FFFFFF" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter TargetName="ExpandPath" Property="UIElement.RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" CenterX="3" CenterY="3" />
</Setter.Value>
</Setter>
<Setter TargetName="ExpandPath" Property="Shape.Fill" Value="#FF595959" />
<Setter TargetName="ExpandPath" Property="Shape.Stroke" Value="#FF262626" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
<Border x:Name="Bd"
Grid.Column="1"
HorizontalAlignment="Stretch"
Background="{TemplateBinding Panel.Background}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
SnapsToDevicePixels="True">
<ContentPresenter x:Name="PART_Header"
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
Content="{TemplateBinding HeaderedContentControl.Header}"
ContentSource="Header"
ContentStringFormat="{TemplateBinding HeaderedItemsControl.HeaderStringFormat}"
ContentTemplate="{TemplateBinding HeaderedContentControl.HeaderTemplate}"
ContentTemplateSelector="{TemplateBinding HeaderedItemsControl.HeaderTemplateSelector}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
<ItemsPresenter x:Name="ItemsHost"
Grid.Row="1"
Grid.Column="1" />
</Grid>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="TreeViewItem.IsExpanded" Value="False">
<Setter TargetName="ItemsHost" Property="UIElement.Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="ItemsControl.HasItems" Value="False">
<Setter TargetName="Expander" Property="UIElement.Visibility" Value="Hidden" />
</Trigger>
<Trigger Property="TreeViewItem.IsSelected" Value="True">
<Setter TargetName="Bd" Property="Panel.Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="TreeViewItem.IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter TargetName="Bd" Property="Panel.Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
</MultiTrigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
At the moment I do not seem to be able to combine those two. Perhaps it's already too late here.
Where should I put the style in the template to have FullRowSelect and keep the selection when focus is lost?
Remove the <Style> tags around the two color brush definitions... in other words, make the color brushes direct Resources of the TreeView rather than wrapped inside of a Style.
I want to change the behaviour of the editable ComboBox. This is the behaviour I want:
Make the TextBox (PART_EditableTextBox) only visible when IsEditable is true and when the ComboBox is open. I've worked this out in the ControlTemplate.Triggers part:
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsEditable" Value="True" />
<Condition Property="IsDropDownOpen" Value="True" />
</MultiTrigger.Conditions>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
</MultiTrigger>
The problem is that when the PART_EditableTextBox is hidden, the content is not shown. So the ComboBox stays blank after I've selected an item. This is only true when IsEditable = true.
Below is the complete ComboBox template code.
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Animations.xaml"/>
<ResourceDictionary Source="Brushes.xaml"/>
</ResourceDictionary.MergedDictionaries>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<ControlTemplate x:Key="EditableComboBoxToggleButton" TargetType="ToggleButton">
<ControlTemplate.Resources>
</ControlTemplate.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<!-- The drop down button on the right -->
<Border Grid.ColumnSpan="2" BorderBrush="#FFFFFFFF" BorderThickness="1,1,1,1" CornerRadius="4,4,4,4">
<Border x:Name="Border" Background="{StaticResource ButtonBaseBrush}" BorderBrush="{StaticResource ButtonInnerBorderBrush}" BorderThickness="1,1,1,1" CornerRadius="4,4,4,4">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.507*"/>
<RowDefinition Height="0.493*"/>
</Grid.RowDefinitions>
<Border Opacity="0" HorizontalAlignment="Stretch" x:Name="glow" Width="Auto" Grid.RowSpan="2" CornerRadius="4,4,4,4" Background="{StaticResource ButtonLitBrush}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Width="Auto" Grid.RowSpan="2"/>
<Border HorizontalAlignment="Stretch" Margin="0,0,0,0" x:Name="shine" Width="Auto" CornerRadius="4,4,0,0" Background="{StaticResource ButtonGlowOverlay}" />
</Grid>
</Border>
</Border>
<!-- The white area where the selected item is displayed (also part of the button) -->
<Border
Grid.Column="0"
CornerRadius="2,0,0,2"
Margin="1"
Background="{StaticResource WindowBackgroundBrush}"
BorderBrush="Black"
BorderThickness="1" />
<!-- The down-arrow -->
<Path
x:Name="Arrow"
Grid.Column="1"
Fill="White"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter Property="Opacity" TargetName="shine" Value="0.4"/>
<Setter Property="Background" TargetName="Border" Value="#DCE38819"/>
<Setter Property="Visibility" TargetName="glow" Value="Hidden"/>
</Trigger>
<Trigger Property="ToggleButton.IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Timeline1}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard x:Name="Timeline2_BeginStoryboard" Storyboard="{StaticResource Timeline2}"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
<Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
</ControlTemplate>
<Style x:Key="EditableGlassComboBox" TargetType="ComboBox">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="Height" Value="34" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton
Name="ToggleButton"
Template="{StaticResource EditableComboBoxToggleButton}"
IsEnabled="{TemplateBinding IsEnabled}"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
</ToggleButton>
<ContentPresenter
Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="3,3,23,3"
VerticalAlignment="Center"
HorizontalAlignment="Stretch" />
<TextBox x:Name="PART_EditableTextBox"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Red"
Grid.Column="0"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
FontSize="16"
Margin="5,5,23,5"
Focusable="True"
Visibility="Collapsed"
IsReadOnly="{TemplateBinding IsReadOnly}"/>
<Popup
Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid
Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border
x:Name="DropDownBorder"
Background="{StaticResource WindowBackgroundBrush}"
BorderThickness="1"
BorderBrush="{StaticResource ComboItemsBorderBrush}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsEditable" Value="True" />
<Condition Property="IsDropDownOpen" Value="True" />
</MultiTrigger.Conditions>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
I've solved my problem by completely ignoring the ComboBox and creating my own UserControl that has a TextBox and a Popup with a ListBox. In code behind I've added filtering and popup up / closing the popup at the right time.
You have to put a TextBlock or a ContentPresenter behind the TextBox (bound to the same value) so when you hide the TextBox the TextBlock becomes visible and shows the selected value.
The easiest way to accomplish this is to but them in the same Grid:
<Grid>
<ContentPresenter Content="{TemplateBinding Text}"/>
<TextBox x:Name="PART_EditableTextBox"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Red"
Grid.Column="0"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
FontSize="16"
Margin="5,5,23,5"
Focusable="True"
Visibility="Collapsed"
IsReadOnly="{TemplateBinding IsReadOnly}"/>
</Grid>