I'm using Prism for UI composition and would need a way to switch the active view by a RadioButton. I want a group of RadioButtons that would change the desired view when checked. I thought the TabControl would be perfect for this. I thought I could just use a style to change the template of the TabItem to a RadioButton, but it is not switching tabs with the RadioButton is selected. Here's the template I have for the TabItem
<ControlTemplate TargetType="{x:Type TabItem}">
<RadioButton IsChecked="{TemplateBinding IsSelected}"
Content="{TemplateBinding Header}" />
</ControlTemplate>
I thought that should make the tab selected when the RadioButton is checked, but that doesn't appear to happen. What am I doing wrong or is there another way to achieve the same result?
Also is there a way to make the first view of the TabControl active? I tried SelectedIndex="0" on the tab control, but that doesn't seem to set the IActiveAware.IsActive on the view.
Here is the exact code that I'm using for styling the TabControl and TabItem
<Style TargetType="{x:Type TabItem}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Foreground" Value="{StaticResource mainRegionControlForegroundBrush}"></Setter>
<Setter Property="Header" Value="{Binding Content.DataContext.Title, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<RadioButton IsChecked="{TemplateBinding IsSelected}" Content="{TemplateBinding Header}" Foreground="{TemplateBinding Foreground}" Margin="{TemplateBinding Margin}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TabControl}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local" ClipToBounds="True" SnapsToDevicePixels="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel IsItemsHost="True" Orientation="Horizontal" Margin="10,0"/>
<ContentPresenter Grid.Row="1" Name="PART_SelectedContentHost" Content="{TemplateBinding TabControl.SelectedContent}" ContentSource="SelectedContent" ContentTemplate="{TemplateBinding TabControl.SelectedContentTemplate}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"></ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I figured it out. TemplateBinding wasn't updating the parent property, so IsSelected was never set on the TabItem. I changed the binding to
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
and it worked.
You simply need to define a new ControlTemplate for the RadioButton that uses a Border element:
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<ControlTemplate x:Key="TabTemplate" TargetType="{x:Type RadioButton}">
<Border BorderBrush="Black" Background="{TemplateBinding Background}"
BorderThickness="1,1,1,0" CornerRadius="5,5,0,0" Padding="5">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Template" Value="{StaticResource TabTemplate}" />
<Setter Property="Height" Value="26" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="LightGray" />
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<RadioButton Content="Tab 1" />
<RadioButton Content="Tab 2" />
<RadioButton Content="Tab 3" />
</StackPanel>
I also added a basic Trigger so that you can see how to Style the selected item differently from the other tabs.
UPDATE >>>
Sorry, I clearly didn't read your question properly. To do it the other way around, it's a lot more work and unfortunately, you are going to have to do your bit because there is just too much code. So to start with, your example code didn't work because you were trying to define a new ControlTemplate for the TabControl, whereas you actually just need to define one for the TabItem.
The first step to do this is to actually define a new ControlTemplate for the whole TabControl which includes the ControlTemplate for the TabItem. Your example didn't work because you failed to replicate a lot of parts of the default ControlTemplate, so we need to do that. How? Well we can find the default ControlTemplate in the TabControl Styles and Templates page on MSDN.
So after looking at that, you'll understand why I can't put all that code here. At first, you basically need to use that exact XAML to reproduce the default ControlTemplate... when it is all working as normal, then you can start to tweak it to your requirements. If you look down the linked page, you'll see this:
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
...
This is where the default ControlTemplate for the TabItem starts. Looking further down, underneath the VisualStateManager.VisualStateGroups, you should see this:
<Border x:Name="Border"
Margin="0,0,-4,0"
BorderThickness="1,1,1,1"
CornerRadius="2,12,0,0">
<Border.BorderBrush>
<SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
</Border.BorderBrush>
<Border.Background>
<LinearGradientBrush StartPoint="0,0"
EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="{DynamicResource ControlLightColor}"
Offset="0.0" />
<GradientStop Color="{DynamicResource ControlMediumColor}"
Offset="1.0" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"
RecognizesAccessKey="True" />
</Border>
This is what defines what a TabItem should look like and is where you need to add your RadioButton (instead of this Border and it's contents). You'll probably also need to remove or adjust anything that references the old controls, eg. in the VisualStateManager.VisualStateGroups section.
Related
I have a ToggleButton in my window and styled in my ResourceDictionary. The reason why it's in the ResourceDictionary is because I have several or more ToggleButton soon which has to have the same look.
<Style x:Key="Standardbutton" TargetType="{x:Type ToggleButton}">
<Setter Property="FontSize" Value="18" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="Resources/Standard_Button_Normal.png" />
</Setter.Value>
</Setter>
<Setter Property="Height" Value="56" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Name="border" BorderThickness="0" Padding="0,0" BorderBrush="DarkGray" CornerRadius="0" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Left" VerticalAlignment="Center" Name="content" Margin="15,0,0,0"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="Resources/Standard_Button_Pressed.png" />
</Setter.Value>
</Setter>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFF9CE7B" Offset="0"/>
<GradientStop Color="#FFE88C41" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now this ToggleButton style has a default background and also when "IsChecked" is true, it will have different background (as you can see on my XAML code above).
Now these toggle buttons has to have icon + text combined, like what I did here (sorry for my lame XAML code)
<ToggleButton Style="{DynamicResource Standardbutton}" Margin="0,0,0,4">
<StackPanel Orientation="Horizontal">
<Image Source="Resources/scan_26x26.png" />
<TextBlock Text="Scan"/>
</StackPanel>
</ToggleButton>
The question is, how can I have a different icon when the ToggleButton is checked (IsChecked=True)?
Here are some images that might help you to understand the question
Normal ToggleButton Style
IsChecked=True Style
My design goal is to have a different icon when IsChecked=True
Add both images to the control template, and bind their Visibility property to the IsChecked property (use an IValueConverter to convert from true/false to the appropriate Visibility enum value).
<ToggleButton Style="{DynamicResource Standardbutton}" Margin="0,0,0,4">
<StackPanel Orientation="Horizontal">
<Image Source="Resources/scan_26x26.png"
Visibility="{Binding
RelativeSource={RelativeSource AncestorType=ToggleButton},
Path=IsChecked,
Converter={StaticResource BoolToVisibleConverter}}" />
<Image Source="Resources/anotherimage.png"
Visibility="{Binding
RelativeSource={RelativeSource AncestorType=ToggleButton},
Path=IsChecked,
Converter={StaticResource BoolToCollapsedConverter}}" />
<TextBlock Text="Scan"/>
</StackPanel>
</ToggleButton>
I used two converters BoolToVisibleConverter and BoolToCollapsedConverter, but you could also use a ConverterParameter to accomplish the same thing.
I am having trouble finding how to not allow my ListBox to highlight the item selected. I know that I didn't add a trigger to highlight the item.
<ListBox Name="CartItems" ItemsSource="{Binding}"
ItemTemplate="{StaticResource TicketTemplate}"
Grid.Row="3" Grid.ColumnSpan="9" Background="Transparent"
BorderBrush="Transparent">
</ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Content.IsSelected, Mode=TwoWay, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
Late answer, but there's a much better and simpler solution:
<ListBox>
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</ListBox.Resources>
</ListBox>
This allows you to have a LisBox that looks just like an itemscontrol, but has support for selection.
Edit: How it works
This alters "colors of the system", in other words your windows theme, only for this ListBox and its children (we actually want to target the ListboxItem).
For example hovering a ListboxItem usually gives it a deep blue background, but here we set it to transparent (HighlightBrushKey).
Edit (30 June 2016):
It seems for latest Windows version this is not enough anymore, you also need to redefine InactiveSelectionHighlightBrushKey
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Transparent" />
Thanks to #packoman in the comments
removing the highlighting completely feels very odd, as you dont know if you've selected anything, but here's a version of the control template that uses WhiteSmoke (which is very subtle) instead of Blue
<Window.Resources>
<Style x:Key="ListBoxItemStyle1" TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Transparent"/>
<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="2,0,0,0"/>
<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>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="WhiteSmoke"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<ListBox HorizontalAlignment="Left" VerticalAlignment="Top" ItemContainerStyle="{DynamicResource ListBoxItemStyle1}">
<ListBoxItem Content="Item1"/>
<ListBoxItem Content="Item2"/>
<ListBoxItem Content="Item3"/>
<ListBoxItem Content="Item4"/>
<ListBoxItem Content="Item5"/>
<ListBoxItem Content="Item6"/>
</ListBox>
</Grid>
here's what worked for me.
<Style x:Key="ListBoxNoHighlight" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Transparent"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
In the Properties tab, there is an Enabled Field with 2 options, true and false. By turning this to false, the Listbox remains white and selection is not avaliable. Just figured this out!
I'm talking about a trick I did in my WP8 app.
I added a transparent frame image above it (the image's border was seen, think of it like a picture frame). The scroll was functional, any manipulation event was firing just that the Listbox items weren't selected anylonger.
<Grid
Grid.Row="0"
Margin="10,15"
Background="#FF008F88">
<ListBox
x:Name="listBox_content"
Margin="20,15"
VirtualizingStackPanel.VirtualizationMode="Recycling">
</ListBox>
<!-- TV image, middle is transparent so the ListBox can be seen -->
<Image
x:Name="image_tv"
Source="/Assets/Images/tvFrame.png"
Stretch="Fill"/>
<!---->
</Grid>
I guess this could work with a full transparent image set to Fill as well.
You will have to re-template ListBoxItem. In the default template, it has a trigger that highlights itself when IsSelected property is true. You just have to create a template that does not have that trigger.
I think you need to create a custom control template for the ListBoxItem, and include the trigger to change the background color to "Transparent" when the item is selected. Here is an example of how you can do this:
<ListBox x:Name="MyListBox">
<ListBox.Resources>
<ControlTemplate x:Key="ListBoxItemControlTemplate" TargetType="ListBoxItem">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="Content" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" TargetName="Bd" Value="Transparent"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template" Value="{StaticResource ListBoxItemControlTemplate}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I have to develop a customized tab control and decided to create it with WPF/XAML, because I planned to learn it anyway. It should look like this when it's finished:
I made good progress so far, but there are two issues left:
Only the first/last tab item should have a rounded upper-left/bottom-left corner. Is it possible to modify the style of these items, similar to the way I did with the selected tab item?
The selected tab item should not have a border on its right side. I tried to accomplish this with z-index and overlapping, but the results were rather disappointing. Is there any other way to do this?
XAML:
<Window x:Class="MyProject.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestWindow" Height="350" Width="500" Margin="5" Background="LightGray">
<Window.Resources>
<LinearGradientBrush x:Key="SelectedBorderBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="Gray" Offset="0.965"/>
<GradientStop Color="WhiteSmoke" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<Style TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<DockPanel>
<Border
Panel.ZIndex="50"
Margin="0,100,-1,0"
Background="#FFAAAAAA"
BorderBrush="Gray"
CornerRadius="7,0,0,7"
BorderThickness="1">
<TabPanel
Margin="0,0,0,0"
IsItemsHost="True" />
</Border>
<Border
Background="WhiteSmoke"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="7,7,7,0" >
<ContentPresenter
ContentSource="SelectedContent" />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border"
Background="#FFAAAAAA"
CornerRadius="7,0,0,0"
BorderBrush="Gray"
BorderThickness="0,0,0,1"
Panel.ZIndex="50"
Margin="0,0,0,0"
>
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Left"
ContentSource="Header"
Margin="10,10,10,10"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter Property="Margin" Value="0,0,-2,0" />
<Setter TargetName="Border"
Property="BorderBrush"
Value="{StaticResource SelectedBorderBrush}"/>
<Setter TargetName="Border"
Property="Background"
Value="WhiteSmoke" />
<Setter TargetName="Border"
Property="CornerRadius"
Value="0,0,0,0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TabControl Name="_menuTabControl" TabStripPlacement="Left" Margin="5">
<TabItem Name="_tabItem1" Header="First Tab Item" ></TabItem>
<TabItem Name="_tabItem2" Header="Second Tab Item" >
<Grid />
</TabItem>
<TabItem Name="_tabItem3" Header="Third Tab Item" >
<Grid />
</TabItem>
</TabControl>
</Grid>
Edit: Thanks to Vlad, I could fix the second problem with a gradient border brush. See updates XAML for the solution.
Edit: Vlad fixed the first problem.
For the second problem, you should perhaps try to remove the clipping? Beware however of the possible issues.
For the first problem, you should try style trigger on property IsSelected. (Edit: I see, you are doing it exactly this way.) Have a look how this is implemented at the default template at MSDN. Note that they are using ZIndex, too.
Edit:
I found a workaround for your first/last tab problem. You need to use attached properties to designate the first/last tab:
In your TestWindow class you define attached property:
public static bool GetIsFirstTab(DependencyObject obj)
{
return (bool)obj.GetValue(IsFirstTabProperty);
}
public static void SetIsFirstTab(DependencyObject obj, bool value)
{
obj.SetValue(IsFirstTabProperty, value);
}
public static readonly DependencyProperty IsFirstTabProperty =
DependencyProperty.RegisterAttached("IsFirstTab", typeof(bool),
typeof(TestWindow), new UIPropertyMetadata(false));
Then, in your first tab you set this property:
<Window x:Class="MyProject.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyProject"
...
/>
...
<TabItem Name="_tabItem1" Header="First Tab Item"
local:TestWindow.IsFirstTab="true">
</TabItem>
Then, you should define a trigger for it:
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border"
Property="Background"
Value="WhiteSmoke" />
</Trigger>
<Trigger Property="local:Window1.IsFirstTab" Value="True">
<Setter TargetName="Border"
Property="Background"
Value="Red" />
</Trigger>
This must help.
The same trick would work with last tab. Or you can have a number instead of bool as attached property.
This is my XAML so far.
<ScrollViewer Grid.Column="1" Grid.RowSpan="2">
<ListBox Background="Black" ItemsSource="{Binding Path=ActiveLog}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Black">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Foreground="White">
<TextBlock >Date:</TextBlock>
<TextBlock Text="{Binding Path=LogDate}"/>
</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" Foreground="White">
<TextBlock >Severity:</TextBlock>
<TextBlock Text="{Binding Path=Severity}"/>
</TextBlock>
<TextBlock Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Foreground="LightGray" Text="{Binding Path=Message}"></TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Template>
<ControlTemplate>
<StackPanel Background="Black" IsItemsHost="True" >
</StackPanel>
</ControlTemplate>
</ListBox.Template>
</ListBox>
</ScrollViewer>
The only problem is that the selected item has a blue box to the right. I assume there is a way to change the selection color, but I can't find it.
<UserControl.Resources>
<Style x:Key="myLBStyle" TargetType="{x:Type ListBoxItem}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent"/>
</Style.Resources>
</Style>
</UserControl.Resources>
and
<ListBox ItemsSource="{Binding Path=FirstNames}"
ItemContainerStyle="{StaticResource myLBStyle}">
You just override the style of the listboxitem (see the: TargetType is ListBoxItem)
Or you can apply HighlightBrushKey directly to the ListBox. Setter Property="Background" Value="Transparent" did NOT work. But I did have to set the Foreground to Black.
<ListBox ... >
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
</Style.Triggers>
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
</Style.Resources>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
You need to use ListBox.ItemContainerStyle.
ListBox.ItemTemplate specifies how the content of an item should be displayed. But WPF still wraps each item in a ListBoxItem control, which by default gets its Background set to the system highlight colour if it is selected. You can't stop WPF creating the ListBoxItem controls, but you can style them -- in your case, to set the Background to always be Transparent or Black or whatever -- and to do so, you use ItemContainerStyle.
juFo's answer shows one possible implementation, by "hijacking" the system background brush resource within the context of the item style; another, perhaps more idiomatic technique is to use a Setter for the Background property.
I had to set both HighlightBrushKey and ControlBrushKey to get it to be correctly styled. Otherwise, whilst it has focus this will correctly use the transparent HighlightBrusKey. Bt, if the control loses focus (whilst it is still highlighted) then it uses the ControlBrushKey.
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</Style.Resources>
When Using .Net 4.5 and above, use InactiveSelectionHighlightBrushKey instead of ControlBrushKey:
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Transparent" />
</Style.Resources>
Hope this helps someone out.
I've tried various solutions and none worked for me, after some more research I've found a solution that worked for me here
https://gist.github.com/LGM-AdrianHum/c8cb125bc493c1ccac99b4098c7eeb60
<Style x:Key="_ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="_Border"
Padding="2"
SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="_Border" Property="Background" Value="Yellow"/>
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ListBox ItemContainerStyle="{DynamicResource _ListBoxItemStyle}"
Width="200" Height="250"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<ListBoxItem>Hello</ListBoxItem>
<ListBoxItem>Hi</ListBoxItem>
</ListBox>
I posted it here, as this is the first google result for this problem so some others may find it useful.
You have to create a new template for item selection like this.
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border
BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<ContentPresenter
Content="{TemplateBinding ContentControl.Content}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
If selection is not important, it is better to use an ItemsControl wrapped in a ScrollViewer. This combination is more light-weight than the Listbox (which actually is derived from ItemsControl already) and using it would eliminate the need to use a cheap hack to override behavior that is already absent from the ItemsControl.
In cases where the selection behavior IS actually important, then this obviously will not work. However, if you want to change the color of the Selected Item Background in such a way that it is not visible to the user, then that would only serve to confuse them. In cases where your intention is to change some other characteristic to indicate that the item is selected, then some of the other answers to this question may still be more relevant.
Here is a skeleton of how the markup should look:
<ScrollViewer>
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
In WPF, we are creating custom controls that inherit from button with completely drawn-from-scratch xaml graphics. We have a border around the entire button xaml and we'd like to use that as the location for updating the background when MouseOver=True in a trigger. What we need to know is how do we update the background of the border in this button with a gradient when the mouse hovers over it?
In your ControlTemplate, give the Border a Name and you can then reference that part of its visual tree in the triggers. Here's a very brief example of restyling a normal Button:
<Style
TargetType="{x:Type Button}">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="customBorder"
CornerRadius="5"
BorderThickness="1"
BorderBrush="Black"
Background="{StaticResource normalButtonBG}">
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger
Property="IsMouseOver"
Value="True">
<Setter
TargetName="customBorder"
Property="Background"
Value="{StaticResource hoverButtonBG}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If that doesn't help, we'll need to know more, probably seeing your own XAML. Your description doesn't make it very clear to me what your actual visual tree is.
You would want to add a trigger like this...
Make a style like this:
<Style x:Key="ButtonTemplate"
TargetType="{x:Type Button}">
<Setter Property="Foreground"
Value="{StaticResource ButtonForeground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type Button}">
<Grid
SnapsToDevicePixels="True"
Margin="0,0,0,0">
<Border Height="20"
x:Name="ButtonBorder"
BorderBrush="{DynamicResource BlackBorderBrush}">
<TextBlock x:Name="button"
TextWrapping="Wrap"
Text="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}"
SnapsToDevicePixels="True"
Foreground="#FFFFFFFF"
Margin="6,0,0,0"
VerticalAlignment="Center"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<!-- Disabled -->
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="ButtonBorder"
Property="Background"
Value="{DynamicResource ButtonBackgroundMouseOver}" />
<Setter TargetName="ButtonBorder"
Property="BorderBrush"
Value="{DynamicResource ButtonBorderMouseOver}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then add some resources for the gradients, like this:
<LinearGradientBrush x:Key="ButtonBackgroundMouseOver"
EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="#FF000000"
Offset="0.432"/>
<GradientStop Color="#FF808080"
Offset="0.9"/>
<GradientStop Color="#FF848484"
Offset="0.044"/>
<GradientStop Color="#FF787878"
Offset="0.308"/>
<GradientStop Color="#FF212121"
Offset="0.676"/>
</LinearGradientBrush>
Please let me know if you need more help with this.