Static Resource Style
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Red"></Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="Green" />
</Trigger>
</Style.Triggers>
</Style>
Toggle Button Code
<ToggleButton Grid.Row="3" Grid.Column="1" ToolTip="Toggle to Show and Hide Date" IsChecked="True" Cursor="Hand">
<ToggleButton.Style>
<Style TargetType="{StaticResource ToggleButton}">
<Setter Property="Content" Value="No Date" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="Date" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
But I'm unable to set the content getting error as Content is not recognized or inaccessible.
I'm not a frequent user of WPF.
Thanks
In your Toggle Button Code, Change
<Style TargetType="{StaticResource ToggleButton}">
to
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource {x:Type ToggleButton}}">
You can have a style defined for a control globally that is/may apply to all controls of that type, but when you have to give individual control some extra styling you can do that by creating a style within the control and base that style on the global style.
This basedOn can be done on style x:Type (as in my answer), or can be based on x:Name as well if you want to base it on a specific style.
Related
I created a simple style in WPF and I cannot figure out what case A works, but not case B.
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter
TextBlock.Foreground="Red"
TextElement.Foreground="Yellow"
Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Case A:
<Button Content="Test A"/> // background is Yellow
Case B:
<Button>
<TextBlock Text="Test B"/> // background is black
</Button>
I would like to create a style for a button that change text color of its content via the ContentPresenter.
Could someone explains what is missing to make case B to work?
(Ideally it should work with any content that have a Foreground property, not only TextBlocks).
Thanks in advance,
Thank you Clemens, but in fact I would like to change foreground of one part of the template only, not the foreground of the control itself. Button is just a simple example here.
I am using the ContentPresenter in triggers too:
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="#CCFFFFFF"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="#66FFFFFF"/>
</Trigger>
</ControlTemplate.Triggers>
Set the Button's Foreground property via another Setter:
<Style TargetType="Button">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Alternatively, add a TextBlock Style to the ControlTemplate's Resources:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ControlTemplate.Resources>
<Grid>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have a global style (Application.Resources) to set the Foreground of all TextBlocks.
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Brown"/>
</Style>
This works fine.
Now I try to override the Foreground of the TextBlock inside of a selected ListBoxItem, which is part of default ContentPresenter content.
I created a new global style for the ListBoxItem:
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="Orange" />
<Setter Property="Background" Value="Aqua"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Background="{TemplateBinding Background}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Brown" />
<Setter Property="Foreground" Value="Aqua" />
</Trigger>
</Style.Triggers>
</Style>
The background works fine.
But Foreground has still the brush form de global style from the TextBlock.
Which is the best way to set the Foreground in a solution that works with Binding?
This is an example of why defining an implicit application-wide TextBlock style is usually a bad idea.
But you should be able to override it by adding a default style to to <ContentPresenter.Resources>:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Background="{TemplateBinding Background}">
<ContentPresenter>
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{x:Null}" />
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
I have made a BaseStyle, which looks like this:
<Style x:Key="BaseStyle" TargetType="{x:Type Control}">
<Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Padding" Value="8,5,3,3" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Control}">
<Grid>
<Border x:Name="BorderBase" Background="White" BorderThickness="1,1,1.4,1.4" BorderBrush="Silver" CornerRadius="4" />
<Label x:Name="TextPrompt" Content="{TemplateBinding Tag}" Visibility="Collapsed" Focusable="False" Foreground="Silver"></Label>
<ScrollViewer Margin="0" x:Name="PART_ContentHost" Foreground="{DynamicResource OutsideFontColor}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderThickness" TargetName="BorderBase" Value="1,1,2.4,2.4"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate x:Name="InspectorErrorTemplate">
<StackPanel Orientation="Vertical">
<Border BorderBrush="Red" BorderThickness="1" CornerRadius="4">
<AdornedElementPlaceholder Name="adornerPlaceholder"/>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And have used it this way to apply it to a textbox, which works fine:
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseStyle}" />
Now I thought I can simply use the same style at a textbox of a combobox. So I thought I have to add something in this part:
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="{x:Type TextBox}">
<Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
<ControlTemplate.Triggers>
</ControlTemplate.Triggers>
</ControlTemplate>
However, I cannot add something like BasedOn="{StaticResource BaseStyle}" in the ControlTemplate to make e.g. the textbox to get a different border when it receives the focus (see IsFocused Trigger in the BaseStyle), or a red curved corner in case the validation is triggered... What am I doing wrong?
Hi you are working with different border color for different text-box that is the only problem here. There are several other options but I feel the following option is good to go.
You can create your own UserControl keeping a TextBox inside it. You can add a new DependencyProperty- BorderColor property in your UserControl. So that according to the BorderColor property value internally you can change the color of the border. So here you don't have to worry about multiple Style or any inheritance.
Isn't it?
The template for a TextBox is fundamentally different than the the template for a ComboBox. So you'll have to have different templates.
You can have one base style to define the shared properties (like Padding, FontFamily, etc.) without defining the Template property. Then make two more styles: one with TargetType set to TextBox; and the other with TargetType set to ComboBox. Each of these styles will be based on your base style and have additional definition for the template (and other properties that are not shared between the two controls).
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'm playing around with wpf and I saw the following article:
WPF ListView Inactive Selection Color
I want to do something similar. I want to put a border around an a listviewitem when it is selected and i want to not change the background color. The reason I want this is I want a color coded listview and I still want to see the color when it's selected, but i want to know it's selected by it having a border around it.
Any ideas?
UPDATE:
I tried the below answer and it got me half way, it does put a border around the listviewitem but it overrides my background color. I can't get the right syntax i tried(Notice the BasedOn):
<Style x:Key="SourceListView" TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="{Binding SourceType, Converter={StaticResource SourceGroupConverter}}"/>
</Style>
<Style x:Key="MyListViewItemStyle" TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource SourceListView}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border
x:Name="Border"
BorderBrush="Transparent"
BorderThickness="1">
<GridViewRowPresenter Columns="{TemplateBinding GridView.ColumnCollection}" Content="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="BorderBrush" Value="Black"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I then tried this:
<Style x:Key="MyListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="{Binding SourceType, Converter={StaticResource SourceGroupConverter}}"/>
<Setter Property="Template">
...//Same as above
</Setter>
</Style>
Both attempts just set the background to white(or transparent I don't know). I know it's just syntax and I'd appreciate another nudge in the right direction :)
Change the ItemContainerStyle on the ListView to a style that doesn't change the background when an item is selected but instead changes the color of a border. Below is an example:
<Style x:Key="MyListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="{Binding SourceType, Converter={StaticResource SourceGroupConverter}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border
x:Name="Border"
BorderBrush="Transparent"
BorderThickness="1"
Background="{TemplateBinding Background}">
<GridViewRowPresenter Columns="{TemplateBinding GridView.ColumnCollection}" Content="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="BorderBrush" Value="Black"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And then use the style like this:
<ListView ItemContainerStyle="{StaticResource MyListViewItemStyle}">
...
</ListView>