I've recently taken to learning WPF for a project. I've been styling a TabControl to fit the colors of a component library I'm using, but these strange white lines have appeared beside each TabItem, but only between items or before the first item.
What are they, and how can I get rid of them? I tried using the inspector provided in Visual Studio but they aren't selectable, which leads me to believe they are some internal part of TabItem, but I'm stuck at this point.
Usage:
<TabControl Grid.Row="1"
TabStripPlacement="Bottom"
BorderBrush="#00000000"
BorderThickness="0"
Resources="{StaticResource TabControlResources}">
<TabItem Header="Story">
<local:Workspace />
</TabItem>
<TabItem Header="Test">
Test Tab
</TabItem>
<TabItem Header="Test">
Test Tab 2
</TabItem>
</TabControl>
And style definition:
<ResourceDictionary x:Key="TabControlResources">
<Style TargetType="TabControl">
<Setter Property="Background"
Value="{StaticResource Fluent.Ribbon.Brushes.RibbonTabControl.Background}"/>
<Setter Property="Foreground"
Value="{StaticResource Fluent.Ribbon.Brushes.IdealForegroundColorBrush}" />
</Style>
<Style TargetType="TabItem">
<Setter Property="Foreground"
Value="{StaticResource Fluent.Ribbon.Brushes.IdealForegroundColorBrush}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background"
Value="{StaticResource Fluent.Ribbon.Brushes.RibbonTabControl.Background}" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background"
Value="{StaticResource Fluent.Ribbon.Brushes.RibbonTabItem.Active.Background}" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
Those are part of the TabItem. You can add the setter in the tab item style within your resource which should do the job:
<Style TargetType="{x:Type TabItem}">
<Setter Property="BorderBrush" Value="Red"/>
</Style>
And the result will be such:
Alternatively:
You can completely remove it, but unfortunately it is part of the template and the template has to be modified:
In Visual studio designer right click on one of the tab items and go to "Edit template" then "Edit a copy".
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
<Border x:Name="mainBorder" BorderBrush="Red" BorderThickness="0" Background="{TemplateBinding Background}" Margin="0">
<Border x:Name="innerBorder" BorderBrush="{StaticResource TabItem.Selected.Border}" BorderThickness="0" Background="{StaticResource TabItem.Selected.Background}" Margin="-1" Opacity="0"/>
</Border>
<ContentPresenter x:Name="contentPresenter" ContentSource="Header" Focusable="False" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
</Grid>
In there you have to modify the BorderThichness of mainBorder and innerBoarder to BorderThickness="0"
Result:
Related
How can I change only the foreground color of a TabItem header text when it is selected or active without changing the foreground of any item inside that TabItemor anything? I'm new to all this so finding it difficult to figure out where in my TabItemstyling can I implement this little feature and how.
The TabControl style I'm using is:
<Style
x:Key="{x:Type TabControl}"
TargetType="{x:Type TabControl}">
<Setter
Property="BorderThickness"
Value="0" />
<Setter
Property="BorderBrush"
Value="Transparent" />
<Setter
Property="Background"
Value="Transparent" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="TabControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition
Height="Auto" />
<RowDefinition
Height="*" />
</Grid.RowDefinitions>
<Border
BorderThickness="0,0,1,1"
BorderBrush="#D0CEBF"
Grid.Row="1">
<Border
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<Border
Background="{TemplateBinding Background}">
<ContentPresenter
ContentSource="SelectedContent" />
</Border>
</Border>
</Border>
<TabPanel
Grid.Row="0"
IsItemsHost="true"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
TargetType="TabItem">
<Setter
Property="BorderThickness"
Value="0" />
<Setter
Property="BorderBrush"
Value="Transparent" />
<Setter
Property="Background"
Value="Transparent" />
<Setter
Property="VerticalContentAlignment"
Value="Center" />
<Setter
Property="HorizontalContentAlignment"
Value="Center" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type TabItem}">
<!--In order to click on the blank part of the TabItem can be successfully selected-->
<Border
Background="Transparent">
<Grid>
<Grid
x:Name="g">
<Path
Fill="{TemplateBinding Background}"
Margin="0,0,0,-1"
Data="M 20,40 L 0,40 0,40 C 4,40 10,36 10,30 L 10,10 C 10,0 16,0 20,0 L 155,0 C 165,0 173,0 ,175,6 L175,30 C 175,30 175,38 182,40 Z" />
</Grid>
<Border
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<ContentPresenter
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</Grid>
</Border>
<!--Add ControlTemplate.Triggers to change the background color of the selected TabItem.-->
<ControlTemplate.Triggers>
<Trigger
Property="IsSelected"
Value="false">
<Setter
Property="Visibility"
TargetName="g"
Value="Hidden" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Adding a trigger in your TabItem control template unfortunately sets the foreground color of the TabItem content, too, when the tab is selected, so this does not work.
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
However, you could add an implicit TextBlock style (without x:Key) inside the ContentPresenter resources. It will be applied automatically only to TextBlocks inside of its scope, not affecting the TabItem content or even other elements in a custom header template other than TextBlocks.
<ContentPresenter
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" >
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}"
Value="true">
<Setter
Property="Foreground"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
Alternatively, a specialized solution is to create a header template and put the trigger there. In this case it does not force an overridden header template to apply the foreground to each TextBlock.
<Setter
Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}"
Value="true">
<Setter
Property="Foreground"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
I am attempting to create a Tab Control Style that basically looks like buttons at the top that are centered and content panel below that displays the tabitem content.
I have am kind of new to templates but what I have so far works very well except one thing. I want to be able to set the default forground color for text elements. Normally I have accomplished this by using the ContentPresenter with dependency elements. So something like this.
<ContentPresenter TextElement.Foreground="White"/>
This basically makes any TextElement Control written by this Presenter to inherit this property.
Now I am trying to do the same thing but it's not working! I believe it has something to do with my style being wrong.
Style:
<Style x:Key="MainMenuTab" TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local" Width="{TemplateBinding Width}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Tab Headers Panel -->
<Grid Grid.Row="0" Background="{StaticResource Brush_ApplicationTabBackground}">
<TabPanel
Name="HeaderPanel"
Grid.Row="0"
Panel.ZIndex="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="{StaticResource Brush_ApplicationTabBackground}"
>
</TabPanel>
</Grid>
<!-- Tab Body -->
<Border
Name="Border"
Grid.Row="1"
Background="{StaticResource Brush_ApplicationBackground}"
BorderBrush="Transparent"
BorderThickness="1"
CornerRadius="2"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2" >
<ContentPresenter
Name="PART_SelectedContentHost"
Margin="4"
ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<!-- Each Tab should look like this -->
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Background="{StaticResource Brush_ApplicationTabBackground}">
<Border Width="50" x:Name="BorderTab" Height="50" Margin="5" BorderThickness="1" ClipToBounds="True" BorderBrush="Transparent" Background="Transparent" CornerRadius="5">
<Rectangle x:Name="BackgroundRec" Fill="Transparent" Stroke="Transparent" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ContentPresenter Name="TheHeaderContentPresenter" Width="50" Height="50" Margin="5" ContentSource="Header" HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="White"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="3"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter Property="Panel.ZIndex" Value="1"/>
</Trigger.Setters>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabBackground}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="0"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabBackground}"/>
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
In my ContentPresenter under ItemContainerStyle has the TextElement.Foreground="White" property but it will not print white text!
My tabcontrol that uses this style looks like this:
<TabControl Grid.Row="2" Style="{StaticResource MainMenuTab}">
<TabItem>
<TabItem.Header>
<TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,5" Text="{x:Static UIStrings:ClientStrings.MainWindow_TabHeader_SingleWaveLength}"></TextBlock>
</TabItem.Header>
<TextBlock>TEST PANEL</TextBlock>
</TabItem>
</TabControl>
I know this is compicated but I would really love this to work.
Solution Found.
Based on HCL's post, I have found a solution. I am experiance the same exact problem I am trying to have the content presenter set the inherited dependence property. instead I simple tell the template to apply the dependance property, that way each tabitem is styled to have this property and therefore sets it for all it's children.
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="TabItem">
<Setter Property="TextElement.Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Background="{StaticResource Brush_ApplicationTabBackground}">
<Border Width="50" x:Name="BorderTab" Height="50" Margin="5" BorderThickness="1" ClipToBounds="True" BorderBrush="Transparent" Background="Transparent" CornerRadius="5">
<Rectangle x:Name="BackgroundRec" Fill="Transparent" Stroke="Transparent" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ContentPresenter Name="TheHeaderContentPresenter" Width="50" Height="50" Margin="5" ContentSource="Header" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="3"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter Property="Panel.ZIndex" Value="1"/>
</Trigger.Setters>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabBackground}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="0"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabBackground}"/>
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
All I've really dont is added the line:
<Setter Property="TextElement.Foreground" Value="White"/>
Before the control template! Also I took the white text out of the content presenter because it is useless.
Check this post, it looks to me as it is the same effect:
ContentPresenter within ControlTemplate cannot change attached dependency property
When using a Popup inside a TreeView in WPF I am running into an issue where the controls inside the popup become unusable. For example, using the following code the ToggleButton inside the popup can only be toggled once and then becomes unable to be toggled back. Is there any way to work around this issue?
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TreeView>
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel>
<ToggleButton>
Button outside popup
</ToggleButton>
<Popup IsOpen="True">
<ToggleButton>
Button inside popup
</ToggleButton>
</Popup>
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</TreeView>
</Grid>
</Page>
The problem is that you are embedding the Popup inside the TreeViewItem, and somehow that is interfering with its built-in functionality. I don't think Popups are meant to be used that way, anyway. Because you can specify the PlacementTarget of a Popup, you can declare them anywhere and then open them at the location you want. The following mark-up demonstrates this with your example:
<StackPanel>
<Popup IsOpen="True" PlacementTarget="{Binding ElementName=buttonPanel}"
Placement="Bottom">
<ToggleButton>
Button inside popup
</ToggleButton>
</Popup>
<TreeView>
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel Name="buttonPanel">
<ToggleButton>
Button outside popup
</ToggleButton>
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</TreeView>
</StackPanel>
As you can see, the Popup can be declared anywhere. You can then use PlacementTarget to put it right where you want. With this change, the ToggleButton works as expected.
Thanks to Charlie finding the issue with using TreeView...
Setting Focusable on the tree view to false also seems to work. But may cause you other issues.
<TreeView Focusable="False">
From what I can tell the issue is which control is taking focus, so it looks like your treeview is taking focus of the mouse click instead of the button.
After discussion with the WPF team I found out that is this is just an issue with WPF.
For my case I was trying to create a drop dialog that is used for each TreeViewItem. I played around with different controls trying to get the looked I needed and I discovered that the Popup portion of a ComboBox worked fine inside a TreeView.
Because of this I ended up using a ComboBox inside the TreeView and forcing the ComboBox to only have one item that is always selected and that item would be my drop dialog. After this I just needed to style the ComboBox to match the look I needed. The code below shows the general idea of what I did.
<TreeView>
<TreeViewItem>
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top">
<ComboBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
</ComboBox.Resources>
<ComboBoxItem IsSelected="True">
<StackPanel Orientation="Vertical">
<Label>Some stuff on the combobox popup</Label>
<RadioButton>Radio Button 1</RadioButton>
<RadioButton>Radio Button 2</RadioButton>
<CheckBox>Check Box</CheckBox>
<Button HorizontalAlignment="Right">Ok</Button>
</StackPanel>
</ComboBoxItem>
</ComboBox>
</TreeViewItem>
</TreeView>
Well I had the same problem where a treeview shows hierarchical items using data template and multiple user control and one of the user control is a toggle button with a pop up in it.
This would freeze totally and would not respond at all. The problem is related to Focus property but setting Focusable to false does not always work.
By looking at the solutions provided above I liked the last one that uses combo box inside a treeviewitem. But it lead to one more problem. Whenever user select the (single) item of the combobox, it would appear in the combobox as a selectedValue and I just want to behave like a toggle with pop up.
Also I wanted to change the triangle on the combobox to ellipsis. So I tried this solution by changing the control template.
Here is my solution:
...
...
<Style x:Key="ComboBoxStyle1" TargetType="{x:Type ComboBox}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ComboBoxFocusVisual}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Padding" Value="4,3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid x:Name="MainGrid" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Popup x:Name="PART_Popup" Margin="1"
AllowsTransparency="true"
IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
Placement="Bottom"
PopupAnimation="Fade">
<Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}" Color="Transparent">
<Border x:Name="DropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="2" CornerRadius="0,4,4,4">
<ScrollViewer CanContentScroll="true">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.DirectionalNavigation="Contained"/>
</ScrollViewer>
</Border>
</Microsoft_Windows_Themes:SystemDropShadowChrome>
</Popup>
<ToggleButton Style="{StaticResource ComboBoxReadonlyToggleButton}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
<Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
<Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
<Setter Property="Background" Value="#FFF4F4F4"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEditable" Value="true">
<Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Padding" Value="3"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="ComboBoxItemStyle1" TargetType="{x:Type ComboBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Padding" Value="3,0,3,0"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<TreeView >
<TreeViewItem IsExpanded="True">
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top"
IsEditable="False"
Style="{StaticResource ComboBoxStyle1}">
<ComboBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
</ComboBox.Resources>
<ComboBoxItem IsSelected="False">
<StackPanel Orientation="Vertical">
<Label>Some stuff on the combobox popup</Label>
<RadioButton>Radio Button 1</RadioButton>
<RadioButton>Radio Button 2</RadioButton>
<CheckBox>Check Box</CheckBox>
<Button HorizontalAlignment="Right">Ok</Button>
</StackPanel>
</ComboBoxItem>
</ComboBox>
</TreeViewItem>
</TreeView>
Is it possible to turn off the selection of a WPF ListView, so when user clicks row, the row is not highlighted?
(source: konim5am at artax.karlin.mff.cuni.cz)
I would like the row 1 to look just like row 0 when clicked.
Possibly related: can I style the look of the hover / selection? Eg. to replace the blue gradient hover look (line 3) with a custom solid color. I have found this and this, unfortunately not helping.
(Achieving the same without using ListView is acceptable too. I'd just like to be able to use logical scrolling and UI virtualization as ListView does)
The XAML for ListView is:
<ListView Height="280" Name="listView">
<ListView.Resources>
<!-- attempt to override selection color -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightColorKey}"
Color="Green" />
</ListView.Resources>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<!-- more columns -->
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
Per Martin Konicek's comment, to fully disable the selection of the items in the simplest manner:
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Focusable" Value="false"/>
</Style>
</ListView.ItemContainerStyle>
...
</ListView>
However if you still require the functionality of the ListView, like being able to select an item, then you can visually disable the styling of the selected item like so:
You can do this a number of ways, from changing the ListViewItem's ControlTemplate to just setting a style (much easier). You can create a style for the ListViewItems using the ItemContainerStyle and 'turn off' the background and border brush when it is selected.
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Background"
Value="{x:Null}" />
<Setter Property="BorderBrush"
Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
...
</ListView>
Also, unless you have some other way of notifying the user when the item is selected (or just for testing) you can add a column to represent the value:
<GridViewColumn Header="IsSelected"
DisplayMemberBinding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
Moore's answer doesn't work, and the page here:
Specifying the Selection Color, Content Alignment, and Background Color for items in a ListBox
explains why it cannot work.
If your listview only contains basic text, the simplest way to solve the problem is by using transparent brushes.
<Window.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#00000000"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="#00000000"/>
</Style.Resources>
</Style>
</Window.Resources>
This will produce undesirable results if the listview's cells are holding controls such as comboboxes, since it also changes their color. To solve this problem, you must redefine the control's template.
<Window.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border SnapsToDevicePixels="True"
x:Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<GridViewRowPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Columns="{TemplateBinding GridView.ColumnCollection}"
Content="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled"
Value="False">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Set the style of each ListViewItem to have Focusable set to false.
<ListView ItemsSource="{Binding Test}" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Here's the default template for ListViewItem from Blend:
Default ListViewItem Template:
<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>
<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.InactiveSelectionHighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
Just remove the IsSelected Trigger and IsSelected/IsSelectionActive MultiTrigger, by adding the below code to your Style to replace the default template, and there will be no visual change when selected.
Solution to turn off the IsSelected property's visual changes:
<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>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
The easiest way I found:
<Setter Property="Focusable" Value="false"/>
Okay, little late to the game, but none of these solutions quite did what I was trying to do.
These solutions have a couple problems
Disable the ListViewItem, which screws up the styles and disables all the children controls
Remove from the hit-test stack, i.e. children controls never get a mouse-over or click
Make it not focusable, this just plain didn't work for me?
I wanted a ListView with the grouping headers, and each ListViewItem should just be 'informational' without selection or hover over, but the ListViewItem has a button in it that I want to be click-able and have hover-over.
So, really what I want is the ListViewItem to not be a ListViewItem at all, So, I over rode the ListViewItem's ControlTemplate and just made it a simple ContentControl.
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ContentControl Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
Further to the solution above... I would use a MultiTrigger to allow the MouseOver highlights to continue to work after selection such that your ListViewItem's style will be:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True" />
<Condition Property="IsMouseOver" Value="False" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
</MultiTrigger.Setters>
</MultiTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
One of the properties of the listview is IsHitTestVisible.
Uncheck it.
Use the code below:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
This is for others who may encounter the following requirements:
Completely replace the visual indication of "selected" (e.g. use some kind of shape), beyond just changing the color of the standard highlight
Include this selected indication in the DataTemplate along with the other visual representations of your model, but,
Don't want to have to add an "IsSelectedItem" property to your model class and be burdened with manually manipulating that property on all model objects.
Require items to be selectable in the ListView
Also would like to replace the visual representation of IsMouseOver
If you're like me (using WPF with .NET 4.5) and found that the solutions involving style triggers simply didn't work, here's my solution:
Replace the ControlTemplate of the ListViewItem in a style:
<ListView ItemsSource="{Binding MyStrings}" ItemTemplate="{StaticResource dtStrings}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
..And the DataTemplate:
<DataTemplate x:Key="dtStrings">
<Border Background="LightCoral" Width="80" Height="24" Margin="1">
<Grid >
<Border Grid.ColumnSpan="2" Background="#88FF0000" Visibility="{Binding RelativeSource={RelativeSource AncestorType=ListViewItem}, Path=IsMouseOver, Converter={StaticResource conBoolToVisibilityTrueIsVisibleFalseIsCollapsed}}"/>
<Rectangle Grid.Column="0" Fill="Lime" Width="10" HorizontalAlignment="Left" Visibility="{Binding RelativeSource={RelativeSource AncestorType=ListViewItem}, Path=IsSelected, Converter={StaticResource conBoolToVisibilityTrueIsVisibleFalseIsCollapsed}}" />
<TextBlock Grid.Column="1" Text="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
</Grid>
</Border>
</DataTemplate>
Results in this at runtime (item 'B' is selected, item 'D' has mouse over):
Below code disables ListViewItem row selection and also allows to add padding, margin etc.
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ListViewItem Padding="0" Margin="0">
<ContentPresenter />
</ListViewItem>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
Below code disable Focus on ListViewItem
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ListView Grid.Row="1" ItemsSource="{Binding Properties}" >
<!--Disable selection of items-->
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Grid Background="{TemplateBinding Background}">
<Border Name="Selection" Visibility="Collapsed" />
<!-- This is used when GridView is put inside the ListView -->
<GridViewRowPresenter Grid.RowSpan="2"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Width="90" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Width="90" CellTemplateSelector="{StaticResource customCellTemplateSelector}" />
</GridView>
</ListView.View>
</ListView>
Another similar control to ListView and ListBox that doesn't offer selection is ItemsControl, consider using that instead.
One more way to disable selection.
<ListView ...>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsEnabled="False"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
It's like
<ListView IsEnabled="False">
but without disabled scroller
I am using IDataErrorInfo to validate and indicate errors in my text boxes. I am finding I have to tab once for the text box and once for the adornerdecorator.
I have an error template:
<ControlTemplate x:Key="ErrorTemplate">
<StackPanel KeyboardNavigation.IsTabStop="False" >
<Border KeyboardNavigation.IsTabStop="False" BorderBrush="Red" BorderThickness="1" Padding="2" CornerRadius="2">
<AdornedElementPlaceholder KeyboardNavigation.IsTabStop="False" />
</Border>
</StackPanel>
</ControlTemplate>
a textbox template:
<Style x:Key="TextBoxInError" TargetType="{x:Type TextBox}">
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Margin" Value="0,5,0,5"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="HorizontalContentAlignment" Value="left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid KeyboardNavigation.IsTabStop="False" >
<Border KeyboardNavigation.IsTabStop="False" x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" Padding="2" CornerRadius="2">
<ScrollViewer IsTabStop="False" Margin="0" x:Name="PART_ContentHost" Style="{DynamicResource SimpleScrollViewer}" Background="{TemplateBinding Background}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors), Converter={StaticResource errorConverter}}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="Gray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and declare a text box like this:
<AdornerDecorator KeyboardNavigation.IsTabStop="False" >
<TextBox Margin="5,5,5,3" x:Name="txtName" IsEnabled="{Binding EditMode}" Validation.ErrorTemplate="{StaticResource ErrorTemplate}"
Text="{Binding ApplicationName, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True, ValidatesOnDataErrors=True}"
Height="25" MaxLength="50" MaxLines="1" Style="{StaticResource TextBoxInError}"/>
</AdornerDecorator>
If the adorner is round one text box as above then I tab once to leave the text box and once to leave the 'adornment' (it seems) If I have the adorner around a stackpanel of text boxes then I tab once each for the text boxes then have to go back through all the 'adornments' in turn. When tabbing through the adornments the focus goes on the red border defined in the control template..
any ideas?
thanks
Add this to the window's resources section:
<Style TargetType="{x:Type Control}">
<Setter Property="Focusable" Value="False"/>
</Style>
For more information look at my blog: http://www.nbdtech.com/blog/archive/2008/05/25/WPF-Problems-with-Keyboard-Focus-When-Using-Validation.aspx