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>
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 am fairly new to WPF, and I am trying to make a custom button where it changes to another specified colour when you hover over it. I have done this with partial success; the only problem is that only the bottom part of the button actually triggers the colour change.
Red highlighted area is the approximate hitbox. (not the long red strip, that's just decoration)
<!-- Button Markup-->
<Button Margin="4,0,4,0" >
<Image Source="{StaticResource closeImg}"></Image>
</Button>
<!-- Button style -->
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#FF2B2B2B"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="Width" Value="28px"/>
<Setter Property="Height" Value="28px"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<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="Red"/>
</Trigger>
</Style.Triggers>
</Style>
I've found that this was a slight quirk with the debug function with WPF and the WindowChrome class. This is fixed by adding the following to the style:
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"></Setter>
your solution seems to be good to me. I've tried the same thing on my vs and everything seems to be just fine. Perhaps there's something else connected with container that holds these buttons, or perhpas something with the image itself. Can you try to set the name for the border inside of a controlTemplate and set the TargetName inside of a trigger? Wonder if that could help
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#FF2B2B2B"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="Width" Value="28px"/>
<Setter Property="Height" Value="28px"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Bd" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
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.
Here is the XAML in my application resources that globally changes all of the Button controls in the application to look and behave like I want:
<Style TargetType="{x:Type Button}" x:Key="MyButtonStyle">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border" CornerRadius="0" BorderThickness="0"
Background="CornflowerBlue" BorderBrush="CornflowerBlue">
<ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True" />
</Border>
<ControlTemplate.Triggers>
<!-- a bunch o' triggers here -->
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
On one of my application's user controls, I would like to change some properties of this button. Here is some XAML that I am using in the UserControl.Resources section now to do this:
<Style x:Key="SpecialButton" TargetType="Button" BasedOn="{StaticResource MyButtonStyle}">
<Setter Property="Width" Value="20" />
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Content" Value=">" />
<Setter Property="Border" Value="#eeeeee" />
<Setter Property="Border.Background" Value="#eeeeee" />
</Style>
The Button controls on my UserControl that I assign the style to of SpecialButton have the correct width, visibility, and content, but these last two attempts do not work. How would I go about changing the background color of the Border with a name of "Border" from the application resource in this SpecialButton style?
What you can do is use TemplateBinding to set the Background property on the control, in the base style. Also in the base style, set the Background color to the default "CornflowerBlue".
<Setter Property="Background" Value="CornflowerBlue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border" Background="{TemplateBinding Background}"
Now you can overwrite the Background in the derived style:
<Style x:Key="SpecialButton" TargetType="Button" BasedOn="{StaticResource MyButtonStyle}">
<Setter Property="Background" Value="#eeeeee" />
(Note that, if you want to use other properties that aren't defined on the Button control -- or, say you wanted to use multiple background colors -- then you'd have to create your own control that inherits Button, and expose the new properties as Dependency Properties.)
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>