I am using a ControlTemplate for my ListBoxItems for a given ListBox. The ControlTemplate is defined in a Style and contains a Rectangle whose Visibility needs to be toggled based on the AlternationIndex. Although I see how to use AlternationIndex to control the background of the ListBoxItem directly, I'm not sure how I use the trigger to reference a named item in my control template. Any input is appreciated:
XAML Excerpt:
<Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid Height="84" Width="700">
<!--
TURN ME ON FOR EVERY EVEN NUMBERED LIST ITEM
-->
<Rectangle x:Name="_listItemBg" Width="700" Height="83" Opacity="0.12">
...
I have tried the following, but to no avail. The correct XAML syntax evades me:
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Rectangle.Visibility" TargetName="_listItemBg" Value="Hidden" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Rectangle.Visibility" TargetName="_listItemBg" Value="Visible" />
</Trigger>
...
Perhaps you forgot to set AlternationCount? In any case, here is a small self-contained working sample based on your code:
<Grid>
<Grid.Resources>
<PointCollection x:Key="sampleData">
<Point>1,2</Point>
<Point>3,4</Point>
<Point>5,6</Point>
</PointCollection>
</Grid.Resources>
<ListBox ItemsSource="{StaticResource sampleData}" AlternationCount="2">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid Height="84" Width="700">
<Rectangle x:Name="_listItemBg" Width="700" Height="83" Fill="Red" Opacity="0.12"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Rectangle.Visibility" TargetName="_listItemBg" Value="Hidden" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Rectangle.Visibility" TargetName="_listItemBg" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
Related
I custom to stlye tab item. but the first child dont same level with content area. picture. How to fix this. default tabcontrol thers border around border around tabitem.
<Application.Resources>
<Style x:Key="BlueOcean" TargetType="{x:Type TabControl}">
<Style.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Height" Value="50" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<StackPanel Name="Panel">
<ContentPresenter
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Panel" Property="Background" Value="LightSkyBlue" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Panel" Property="Background" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
</Style>
</Application.Resources>
TabControl View
<TabControl Style="{DynamicResource BlueOcean}" TabStripPlacement="Left">
<TabItem Header="Home" Content="Home Page" />
<TabItem Header="Settings" Content="Settings Page" />
</TabControl>
I try to create a ListView which doesn't have a hover and selected style but has alternating colors for the ListViewItem's.
To disable the styles I set the ItemContainerStyle. The problem is that the expression ListView.AlternationIndex is somehow allways evaluating to 0 as Christian Mosers WPF Inspector tells me. This results in that the background color for all items is red.
<ListView ItemsSource="{Binding Configuration}" AlternationCount="2" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border>
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="ListView.AlternationIndex" Value="0">
<Setter Property="Background" Value="Red" />
</Trigger>
<Trigger Property="ListView.AlternationIndex" Value="1">
<Setter Property="Background" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
How can I color the items alternating wihout having the selected and hover style?
(The background color of the first item should be red the one of the second blue the one of the third red again and so on)
(The Backgroundcolor, border, padding, margin and so on should not change when the mouse is over an ListViewItem or a ListViewItem is selected)
EDIT: Thanks for the answers. I changed added a template binding to the solution to get rid of the Name property.
<ListView ItemsSource="{Binding Configuration}" AlternationCount="2" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<Trigger Property="ListBox.AlternationIndex" Value="0">
<Setter Property="Border.Background" Value="Red" />
</Trigger>
<Trigger Property="ListBox.AlternationIndex" Value="1">
<Setter Property="Border.Background" Value="Blue" />
</Trigger>
</Style.Triggers>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border Background="{TemplateBinding Background}">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Put the triggers in <ControlTemplate.Triggers>:
<ListView ItemsSource="{Binding Configuration}" AlternationCount="2" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border x:Name="Border">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="Red" TargetName="Border" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="Blue" TargetName="Border" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
The triggers have to be on the control template; the Border doesn't know anything about its parent.
But since the property to set (Background) is on the Border, you have to name it and use TargetName.
<ListView AlternationCount="2" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border Name="border">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" TargetName="border" Value="Red" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" TargetName="border" Value="Blue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListViewItem Content="ABC"/>
<ListViewItem Content="DEF"/>
<ListViewItem Content="GHI"/>
<ListViewItem Content="JKL"/>
</ListView>
This XAML produces the desired result:
WPF /MVVM Pattern
User control with multiple textboxes using validation attributes.
In the following style, everything works as intended- EXCEPT for those with a validation error, the Focused backcolor is not being set, due to the method used in the control template to set the error image.
If I remove the control template, the backcolor is set properly when focused if the validation error is set. With the template, backcolor is always white/default.
Any suggestions on the XAML required to have both - different backcolor when focused and the error image when validation fails?
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="1" />
<Setter Property="ToolTip" Value="{Binding Description}"/>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="LightYellow"/>
</Trigger>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
<!--adds the error image and border, but also prevents background color change OnFocus-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Border
BorderBrush="#d99" x:Name="textBorder" CornerRadius="4"
BorderThickness="2" >
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
</Border>
<Image Name="ErrorImage" Width="24" Height="24" Margin="0,0,4,0"
Source="/Images/error.png" HorizontalAlignment="Right">
</Image>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
You should check out the DependencyProperty precedence rules
What happens here is that the ControlTemplate you define overrides the Style.Triggers defined just before.
What you can do to make it work is to set the actual Style with appropriate Triggers directly inside of the ControlTemplate
Otherwise, as you've seen, WPF will just use the default template for a Grid.
The code should look like that:
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
<!--adds the error image and border, but also prevents background color change OnFocus-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<!-- The trigger about IsFocused should be here!
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="LightYellow"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Border
BorderBrush="#d99" x:Name="textBorder" CornerRadius="4"
BorderThickness="2" >
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
</Border>
<Image Name="ErrorImage" Width="24" Height="24" Margin="0,0,4,0"
Source="/Images/error.png" HorizontalAlignment="Right">
</Image>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
I'm using a WPF Tabcontrol populated with a collection using Itemssource.
<TabControl x:Name="_tabControl" ItemsSource="{Binding TabViewModelList}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding TabCaption}"/>
<Setter Property="Content" Value="{Binding TabContent}"/>
<Setter Property="IsSelected" Value="{Binding IsDefault}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Now I want to set my TabItem-style in my App.xaml(or other resourcefile) like this:
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Background="LightBlue"
BorderBrush="Black"
BorderThickness="1,1,1,1"
CornerRadius="6,6,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="LightGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
..but the ItemContainerStyle, of course overrides the controltemplate.
How do I combine these two so I can load my tabcontrol dynamically and still be able to style my TabItems the way I want to?
Ok... Solved my own problem. Pretty obvious..
Named my template
<Style TargetType="{x:Type TabItem}" x:Key="TabItemTemplate">
Added a BasedOn property like this:
<Style TargetType="TabItem" BasedOn="{StaticResource TabItemTemplate}">
But if I could combine them into one template please let me know...
I've been recently playing with WPF and I've come across a number of problems that I can't solve. I have the following code in my generic.xaml:
<Style TargetType="{x:Type local:ClearButton}">
<Style.Resources>
<con:ValueConverter x:Key="converter" />
</Style.Resources>
<Setter Property="Width" Value="20" />
<Setter Property="Height" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ClearButton}">
<Grid>
<Image Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="/WPF-Libraries;component/Resources/ClearEnabled.png" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BitmapEffect">
<Setter.Value>
<OuterGlowBitmapEffect Opacity="0.5" GlowColor="Red" GlowSize="3" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Source"
Value="/WPF-Libraries;component/Resources/ClearDisabled.png" />
</Trigger>
<!--Binding #1-->
<Trigger Property="{TemplateBinding local:ClearButton.IsPressed}" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<!--Binding #2-->
<ScaleTransform CenterX="CONVERTER BINDING:PASS WIDTH TO CONVERTER" CenterY="CONVERTER BINDING:PASS HEIGHT TO CONVERTER" ScaleX="0.75" ScaleY="0.75" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I can't get Binding #1 to work. I want to bind the trigger to the IsPressed property of the button, what should the binding be? Also what should the binding be for Binding #2 if I want to pass the button's Width and Height to the converter?
Also I could set the trigger this way instead:
<Style TargetType="{x:Type local:ClearButton}">
<Style.Resources>
<con:ValueConverter x:Key="converter" />
</Style.Resources>
<Setter Property="Width" Value="20" />
<Setter Property="Height" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ClearButton}">
<!--Abbreviated-->
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<!--Binding #1-->
<Trigger Property="{TemplateBinding local:ClearButton.IsPressed}" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<!--Binding #2-->
<ScaleTransform CenterX="CONVERTER BINDING" CenterY="CONVERTER BINDING" ScaleX="0.75" ScaleY="0.75" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Which one is better and what would the binding be for Binding #1 and #2?
Both approaches are a little bit off. Your first approach is struggling to reach the IsPressed property using binding, however the Property property of the Trigger object is not a DependencyProperty so it doesn't support binding.
Your second approach is closer to the mark but still wrong, again uses binding on the Property property of the Trigger.
Check this out instead:
<Style TargetType="Button" x:Key="ClearButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<TextBlock
Name="x"
Text="I will change my color when ou press me"
TextAlignment="Center"
VerticalAlignment="Center"
Foreground="Red"
TextWrapping="Wrap"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter
TargetName="x"
Property="Foreground"
Value="Green"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Notice that I put the trigger logic on the control template level (specifying the target element), not on the individual element (the TextBlock in this case).