I have a <ListBox> with custom <ListBox.ItemTemplate> and <DataTemplate> in it:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="5">
<Image Source="{Binding Picture}" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now when I'm choosing the ListBoxItem it gets ugly with blue colored row selection. I'd like to change it. I want to color only border's background and nothing else. Also I want to change MouseOver behavior. I've tried trough triggers, but ContentPresenter doesn't have Background property.
UPD:
Well, I've managed to change the background on MouseEnter and MouseLeave:
<EventTrigger RoutedEvent="Border.MouseEnter">
<BeginStoryboard>
<Storyboard >
<ColorAnimation Storyboard.TargetProperty="Background.Color"
To="LightBlue" Duration="0:0:0.03"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
But still can't change the Background when item's selected. I'm trying through:
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
Doesn't work
The coloring you're looking for is in two Triggers inside the template for ListBoxItem, not the ItemTemplate. To change this you need to edit the ItemContainerStyle for the ListBox. This is the default that can be used as a starting point:
<ListBox>
<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="2,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<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="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" 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="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>
You can do this by using triggers. I have in one of my projects something like this:
<Trigger Property="IsSelected" Value="true">
<Setter Property="Panel.ZIndex" Value="1"/>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource TabItemSelectedBackground}"/>
</Trigger>
Though it doesn't change Border color, it shows how to change the Background. So, maybe try to set this to null. This triggers are part of a custom Style in which a tracking is achieved using IsMouseOver property.
HTH
Related
How can I remove the borders inside RadDatePicker in WPF?
I mean these grey vertical and horizontal lines inside RadCalendar.
In order to change the visual appearance of controls, you have to change their default style or control templates. If you have installed Telerik UI for WPF you can find the default styles for controls here:
C:\Program Files (x86)\Progress\<Your Telerik Version Folder>\Themes.Implicit\WPF40
From your screenshot I guess that you are using the Fluent theme. The resources for the RadDatePicker can be found in \Fluent\Themes\Telerik.Windows.Controls.Input.xaml.
What you describe in your screenshot as a border is actually the background of the calendar control. It only appears to be a border, because the buttons within the calendar have a margin that makes the background visible.
As you can see below, the LayoutRoot Grid defines a margin in the control template of CalendarButton.
<ControlTemplate TargetType="calendar:CalendarButton">
<Grid x:Name="LayoutRoot" Background="Transparent" Margin="{StaticResource CalendarButtonMargin}">
<!-- ...other template code. -->
</ControlTemplate>
In order to remove the margin, copy the CalendarButtonStyle style and remove the Margin in it.
<Style x:Key="MyCalendarButtonStyle" TargetType="calendar:CalendarButton">
<Setter Property="materialControls:MaterialAssist.CornerRadius" Value="0"/>
<Setter Property="materialControls:MaterialAssist.MouseOverBrush" Value="{telerik:FluentResource ResourceKey=MouseOverBrush}"/>
<Setter Property="materialControls:MaterialAssist.PressedBrush" Value="{telerik:FluentResource ResourceKey=PressedBrush}"/>
<Setter Property="materialControls:MaterialAssist.FocusBrush" Value="{telerik:FluentResource ResourceKey=AccentFocusedBrush}"/>
<Setter Property="materialControls:MaterialAssist.CheckedBrush" Value="{telerik:FluentResource ResourceKey=AccentBrush}"/>
<Setter Property="FontFamily" Value="{telerik:FluentResource ResourceKey=FontFamily}"/>
<Setter Property="FontSize" Value="{telerik:FluentResource ResourceKey=FontSize}"/>
<Setter Property="Foreground" Value="{telerik:FluentResource ResourceKey=MarkerBrush}"/>
<Setter Property="Background" Value="{telerik:FluentResource ResourceKey=PrimaryBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{telerik:FluentResource ResourceKey=PrimaryBackgroundBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="MinWidth" Value="38"/>
<Setter Property="MinHeight" Value="38"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="calendar:CalendarButton">
<Grid x:Name="LayoutRoot" Background="Transparent" Margin="0">
<Border x:Name="BorderVisual"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="{TemplateBinding materialControls:MaterialAssist.CornerRadius}"/>
<materialControls:FluentControl x:Name="Fluent" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding materialControls:MaterialAssist.CornerRadius}" IsSmartClipped="True">
<ContentControl x:Name="Content"
Margin="{TemplateBinding Padding}"
Foreground="{TemplateBinding Foreground}"
ContentTemplate="{TemplateBinding ContentTemplate}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
IsTabStop="False"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"/>
</materialControls:FluentControl>
<Border x:Name="FocusVisual"
Background="{x:Null}"
Visibility="Collapsed"
IsHitTestVisible="False"
BorderThickness="{telerik:FluentResource ResourceKey=FocusThickness}"
BorderBrush="{TemplateBinding materialControls:MaterialAssist.FocusBrush}"
CornerRadius="{TemplateBinding materialControls:MaterialAssist.CornerRadius}"/>
<Border x:Name="SelectedVisual"
Background="{x:Null}"
Visibility="Collapsed"
IsHitTestVisible="False"
BorderThickness="{telerik:FluentResource ResourceKey=FocusThickness}"
BorderBrush="{telerik:FluentResource ResourceKey=IconBrush}"
CornerRadius="{TemplateBinding materialControls:MaterialAssist.CornerRadius}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFromCurrentView" Value="False">
<Setter TargetName="BorderVisual" Property="Background" Value="{telerik:FluentResource ResourceKey=AlternativeBrush}"/>
<Setter TargetName="BorderVisual" Property="BorderBrush" Value="{telerik:FluentResource ResourceKey=AlternativeBrush}"/>
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter TargetName="FocusVisual" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="ButtonType" Value="TodayDate">
<Setter TargetName="BorderVisual" Property="Background" Value="{telerik:FluentResource ResourceKey=AccentMouseOverBrush}"/>
<Setter TargetName="BorderVisual" Property="BorderBrush" Value="{telerik:FluentResource ResourceKey=AccentMouseOverBrush}"/>
<Setter Property="materialControls:MaterialAssist.CheckedBrush" Value="{telerik:FluentResource ResourceKey=AccentPressedBrush}"/>
<Setter Property="materialControls:MaterialAssist.MouseOverBrush" Value="{telerik:FluentResource ResourceKey=AccentMouseOverBrush}"/>
<Setter Property="Foreground" Value="{telerik:FluentResource ResourceKey=MarkerInvertedBrush}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="BorderVisual" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(materialControls:MaterialAssist.MouseOverBrush), Mode=OneWay}"/>
<Setter TargetName="BorderVisual" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(materialControls:MaterialAssist.MouseOverBrush), Mode=OneWay}"/>
</Trigger>
<Trigger Property="IsPressed" SourceName="Fluent" Value="True">
<Setter TargetName="BorderVisual" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(materialControls:MaterialAssist.PressedBrush), Mode=OneWay}"/>
<Setter TargetName="BorderVisual" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(materialControls:MaterialAssist.PressedBrush), Mode=OneWay}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Content" Property="Opacity" Value="{telerik:FluentResource ResourceKey=DisabledOpacity}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="{telerik:FluentResource ResourceKey=MarkerInvertedBrush}"/>
<Setter TargetName="FocusVisual" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="BorderVisual" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(materialControls:MaterialAssist.CheckedBrush), Mode=OneWay}"/>
<Setter TargetName="BorderVisual" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(materialControls:MaterialAssist.CheckedBrush), Mode=OneWay}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"/>
<Condition Property="ButtonType" Value="TodayDate"/>
</MultiTrigger.Conditions>
<Setter TargetName="FocusVisual" Property="Visibility" Value="Visible"/>
</MultiTrigger>
<Trigger Property="ButtonType" Value="WeekNumber">
<Setter TargetName="Fluent" Property="IsEnabled" Value="False"/>
<Setter TargetName="BorderVisual" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background, Mode=OneWay}"/>
<Setter TargetName="BorderVisual" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background, Mode=OneWay}"/>
<Setter Property="Foreground" Value="{telerik:FluentResource ResourceKey=AccentBrush}"/>
</Trigger>
<Trigger Property="ButtonType" Value="WeekName">
<Setter TargetName="Fluent" Property="IsEnabled" Value="False"/>
<Setter TargetName="Content" Property="Foreground" Value="{telerik:FluentResource ResourceKey=MarkerBrush}"/>
<Setter TargetName="Content" Property="FontWeight" Value="SemiBold"/>
<Setter TargetName="LayoutRoot" Property="Margin" Value="0"/>
<Setter TargetName="BorderVisual" Property="Visibility" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then create a style a RadCalendar style that uses this CalendarButton style.
<Style x:Key="MyCalendarStyle" TargetType="telerik:RadCalendar" BasedOn="{StaticResource {x:Type telerik:RadCalendar}}">
<Setter Property="DayButtonStyle" Value="{StaticResource MyCalendarButtonStyle}"/>
<Setter Property="MonthButtonStyle" Value="{StaticResource MyCalendarButtonStyle}"/>
<Setter Property="YearButtonStyle" Value="{StaticResource MyCalendarButtonStyle}"/>
<Setter Property="DecadeButtonStyle" Value="{StaticResource MyCalendarButtonStyle}"/>
</Style>
Then create a RadDatePicker style that uses this RadCalendar style.
<Style x:Key="MyDatePickerStyle" TargetType="{x:Type telerik:RadDatePicker}" BasedOn="{StaticResource {x:Type telerik:RadDatePicker}}">
<Setter Property="CalendarStyle" Value="{StaticResource MyCalendarStyle}"/>
</Style>
Now you can apply this style to any date picker like this.
<telerik:RadDatePicker Style="{StaticResource MyDatePickerStyle}"/>
If you want this style to be applied to all RadDatePickers in scope, you can add an implicit style.
<Style TargetType="{x:Type telerik:RadDatePicker}" BasedOn="{StaticResource MyDatePickerStyle}"/>
This is a screenshot of the resulting calendar.
For more information on styling the RadDatePicker, you can refer to the documentation.
I have a WPF ListView that I'm trying to apply a custom style too... primarily I want to make the background of the listview box transparent with no border... and I want to override the highlighted and selected item styles. The default highlight is a semi-transparent blue and the selected item is grey. I'd like to override these in order to customize them. I've followed several threads and tutorials... including this one but, my highlight and selected items remain in the default style. Here's what I have.
<UserControl.Resources>
<ResourceDictionary>
<Style x:Key="ListViewStyle" TargetType="ListView">
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="BorderBrush" Value="Transparent"></Setter>
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Red" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Green" />
</Style.Resources>
</Style>
</ResourceDictionary>
</UserControl.Resources>
....
<ListView Style="{StaticResource ListViewStyle}" ItemsSource="{Binding Path=Items}" ScrollViewer.VerticalScrollBarVisibility="Disabled" SelectedItem="{Binding Path=DataContext.Current" >
<ListView.ItemTemplate>
<DataTemplate DataType="local:Cases">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<!-- Some UI Controls Here -->
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This approach of trying to override the system colours doesn't work on Windows 8 and later.
You need to modify the ControlTemplate of the ListViewItem container.
You can copy the default template into your XAML markup by right-clicking on the ListView in design mode in Visual Studio or in Blend and choose Edit Additional Templates->Edit Generated Item Container (ItemContainerStyle) and then edit it as per your requirements by for example changing the Color properties of the SolidColorBrushes:
<ListView ItemsSource="{Binding Path=Items}" SelectedItem="{Binding Path=DataContext.Current" >
<ListView.Resources>
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="Item.MouseOver.Background" Color="Red"/>
<SolidColorBrush x:Key="Item.MouseOver.Border" Color="#a826A0Da"/>
<SolidColorBrush x:Key="Item.SelectedInactive.Background" Color="#3DDADADA"/>
<SolidColorBrush x:Key="Item.SelectedInactive.Border" Color="#FFDADADA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Background" Color="#3D26A0DA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Border" Color="#FF26A0DA"/>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Padding" Value="4,1"/>
<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="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.MouseOver.Border}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="False"/>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Border}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="True"/>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Border}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate DataType="local:Cases">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<!-- Some UI Controls Here -->
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
First of all, this is not a duplicate of Setting the Inactive Highlight Colour of a WPF ListBox to the Active Highlight Colour. An explanation for that is given below.
Setting:
I have a WPF ListBox in a UserControl that will later be put into an application that uses heavy theming. From the perspective of the UserControl, I don't know in advance what the theming will be like.
Desired behavior:
If the ListBox does not have focus at some point, I still want the selected ListBoxItems to have the same appearance as if the ListBox does have focus.
Additional information:
Note that just setting the colors to some system defaults will not work. Doing so would override the containing application's theming. (That's the reason why this question is not a duplicate of the linked question above.)
Is there a way to realize this, e.g. using XAML?
EDIT: After a bit of research, I think I want to create a copy of the "default" ListBoxItem style ("default" at least in terms of being the default at the level of the UserControl), where all Triggers with Property="Button.IsFocused" Value="False" will not be triggered and all Triggers with Property="Button.IsFocused" Value="True" will always be triggered.
Unfortunately I have no clue where to even start to perform research in how to accomplish this. So any hints towards places where I can start researching would be much appreciated as well.
Summary
It seems like you want to achieve setting the focused style equal to the non-focused style, without editing a theme and doing it in a theme independent way. As far as I know, this isn't possible, primarily because each theme can technically implement ListBoxItem focus behavior in different ways. In fact, I've seen a theme where your desired behavior was the behavior of the ListBoxItem!
How to Modify the Theme
Now if you're open to modifying each theme to suite your needs, read ahead.
If you're modifying the theme globally, you can edit the style for the ListBoxItem directly (after finding out where it exists). If you want the changes applied more specifically, then you'll end up copying the current ListBoxItem style (from whatever theme you're editing) and making changes to it.
A copy of the default ListBoxItem theme is as follows (I used Visual Studio to make the copy). The things you need to change are going to be slightly different for each theme, but the general idea is the same.
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="Item.MouseOver.Background" Color="#1F26A0DA"/>
<SolidColorBrush x:Key="Item.MouseOver.Border" Color="#a826A0Da"/>
<SolidColorBrush x:Key="Item.SelectedInactive.Background" Color="#3DDADADA"/>
<SolidColorBrush x:Key="Item.SelectedInactive.Border" Color="#FFDADADA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Background" Color="#3D26A0DA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Border" Color="#FF26A0DA"/>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Padding" Value="4,1"/>
<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="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.MouseOver.Border}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="False"/>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Border}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="True"/>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Border}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The key part is in the middle:
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="False"/>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Border}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="True"/>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Border}"/>
</MultiTrigger>
This is setting up two different styles for the selected item while focused and while unfocused.
To get your desired behavior, you have one of two options; you can either simply turn it into a simple trigger just on IsSelected, replacing the above chunk with:
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Background}"/>
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Border}"/>
</Trigger>
or you can change the Item.SelectedInactive.Background and Item.SelectedInactive.Border properties to match the active colors (this was above the ListBox style):
<SolidColorBrush x:Key="Item.SelectedInactive.Background" Color="#3D26A0DA"/>
<SolidColorBrush x:Key="Item.SelectedInactive.Border" Color="#FF26A0DA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Background" Color="#3D26A0DA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Border" Color="#FF26A0DA"/>
Generally the first approach is preferred, as it's more clear what's going on.
Additional Constraints
Now, the above copy of the default theme's ListBoxItem will change it for all ListBoxItems. If you want to only change some, then you need to add a key to your "copied style", like so:
<Style x:Key="InactiveLikeActive" TargetType="{x:Type ListBoxItem}">
And then at some level above where you want the style applied (perhaps even just a single ListBox itself), add the following style definition:
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource InactiveLikeActive}" />
For example:
<ListBox>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource InactiveLikeActive}" />
</ListBox.Resources>
<ListBoxItem>One</ListBoxItem>
<ListBoxItem>Two</ListBoxItem>
</ListBox>
Closing Thoughts
While WPF makes it possible to override almost all default appearances, it doesn't necessarily make it easy, or simple to do.
The shortest variant that has been achieved
<ListBox ItemsSource="{Binding ElectrEquipAll}"
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" >
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#1F26A0DA"/>
<Setter Property="BorderBrush" Value="#a826A0Da"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#3D26A0DA"/>
<Setter Property="BorderBrush" Value="#FF26A0DA"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I have a ListBox which has an itemcontainerstyle, it has background color(lets say Green) too in this style, I want to change the background color from MVVM.
The color will change on some specific condition,otherwise the default color(ie Green) should apply.
<ListBox x:Name="lst1" ItemsSource="{Binding DataSource}" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Disabled" Style="{DynamicResource StepListBox}" ItemContainerStyle="{DynamicResource ListBoxItemStyle}" Margin="-10,0,0,0">
//Listbox Items
</ListBox>
and this is my ListboxItemStyle,its defined in a separate xaml file
<Style x:Key="ListboxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Margin" Value="20,0,0,10"/>
<Setter Property="Background" Value="{DynamicResource Green}"/>
<Setter Property="BorderBrush" Value="{DynamicResource TertiaryMediumStroke}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource SecondaryDark}"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="10,10,0,10"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<Grid Margin="0">
<Rectangle x:Name="BgColor" Fill="{DynamicResource TertiaryMediumStroke}" Margin="-10,-10,0,-10" Opacity="0.1"/>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<!--#FFD1EFD6-->
<Setter Property="Background" TargetName="Bd" Value="#FFD7F0DB" />
<Setter Property="Opacity" TargetName="BgColor" Value="0" />
<Setter Property="Foreground" Value="{DynamicResource ForeLight}"/>
</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="Opacity" TargetName="BgColor" Value="0" />
<Setter Property="Foreground" Value="{DynamicResource ForeDisable}"/>
<Setter Property="Background" TargetName="Bd" Value="{StaticResource TertiaryMedium}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I change this in my ViewModel?
When using MVVM, the view models should really know nothing about the views. However, if you really insist on changing UI element colours from the view model, then you can follow this approach. The idea is to have one or more properties with primitive types, such as bool, int, or even enum, that are data bound in the UI. Using DataTriggers, your UI can 'listen' for changes in these properties and update colours accordingly. Take this example:
If you have just one or two colours to update, you can use a bool property and a some DataTriggers:
<Style>
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsElementRed}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
If you have a range of colours to update, you could use a custom enum:
<Style>
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding EnumInstance}" Value="SomeValue">
<Setter Property="Background" Value="Red" />
</DataTrigger>
...
<DataTrigger Binding="{Binding EnumInstance}" Value="SomeOtherValue">
<Setter Property="Background" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
Alternatively, you could also use an IValueConverter to convert between the enum instance and the various required colours.
You'll only need a DataTrigger in your Style on a boolean in your ViewModel layer:
<Style.Triggers>
<DataTrigger Binding="{Binding MyBooleanProperty, Mode=OneWay}" Value="True">
<Setter Property="Background" Value="WhatEverColorYouWant"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="Background" Value="Green"/>
And in your ViewModel:
public bool MyBool {
get { return _firstCondition && _secondCondition && _thirdCondition; }
}
And when one of the condition changes, you'll just want to raise a NotifyPropertyChanged on MyBool
I have a ListView that looks like this:
<ListView x:Name="LocationList"
BorderBrush="{x:Null}"
Margin="50,20,20,50"
ItemsSource="{Binding Locations}" />
And a style and control template like this:
<ControlTemplate x:Key="SelectedTemplate" TargetType="ListViewItem">
<Border SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}" >
<ContentControl SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Margin}"
FontSize="{TemplateBinding FontSize}"/>
</Border>
</ControlTemplate>
<Style x:Name="ListStyle" TargetType="ListViewItem">
<Setter Property="BorderBrush" Value="{x:Null}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="FontSize" Value="30"/>
<Setter Property="Margin" Value="3,3,3,3"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="Template" Value="{StaticResource SelectedTemplate}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="Selector.IsSelectionActive" Value="true" />
</MultiTrigger.Conditions>
<Setter Property="Foreground" Value="Red" />
<Setter Property="Template" Value="{StaticResource SelectedTemplate}" />
</MultiTrigger>
</Style.Triggers>
</Style>
This works as expected when using a mouse; hovering the cursor over a list item activates the "IsMouseOver" style and clicking it activates the "IsSelected" style. However, when using a touch screen clicking on a list item only activates the "IsMouseOver" style and the item is not selected, to select it I have to click the same item again. When holding the finger down (causing a cursor to appear) the "IsMouseOver" style is not activated when I drag my finger across it.