How to make DataTrigger with Style using WPF? [duplicate] - c#

Here is a simple XAML with trigger that should change ToggleButton content when it is checked. But for some reason it doesn't work. I have a silly feeling that I missed something extra small. Appreciate your help
<ToggleButton Content="<">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value=">" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>

You must move Content="<" from ToggleButton to setter of Style.
Example:
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Content" Value="<" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value=">" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Because local value has higher precedence order over Style setters and triggers:
Property system coercion.
Active animations, or animations with a Hold behavior.
3. Local value.
TemplatedParent template properties.
Implicit style.
6. Style triggers.
Template triggers.
8. Style setters.
...
For more information, please see:
MSDN: Dependency Property Value Precedence

You are overriding the Content set by the Trigger by setting the Content attribute at the control level. You want to set it using a Setter within the Style instead:
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Content" Value="<" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value=">" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>

Related

Cannot Change Hovering Color of `ToggleButton`

I am trying to change the hovering color of a toggle button when the button is checked. For some reason, it doesn't work. However, I can change the thickness of the border.
<!--App.xaml-->
<ResourceDictionary>
<Style x:Key="MyStyle" TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="BorderThickness" Value="10"/> <!--works-->
<Setter Property="BorderBrush" Value="Red"/> <!--fails-->
<Setter Property="Background" Value="Red"/> <!--fails-->
</MultiTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
<!--MainWindow.xaml-->
<Grid>
<ToggleButton
Style="{StaticResource MyStyle}"
Content="Button"
HorizontalAlignment="Left"
Margin="271,0,0,0"
VerticalAlignment="Center"
Height="108"
Width="192"
/>
</Grid>
That's because ToggleButton has a ControlTemplate that defines its visual structure - and this template has precedence over style setters.
The template uses a Border element with x:Name Border to render the ToggleButton's border, and a Grid named ContentPresenter to host the button's content.
The template also defines triggers that modify the Border's properties when the button is in the MouseOver state - and these have a higher precedence than style triggers.
To override this behavior, you need to use template bindings in your style:
<Style x:Key="MyStyle" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="Border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
...
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="10"/>
</MultiTrigger>
</Style.Triggers>
</Style>
Now the style setters will update the properties of the Border element defined in the template, overriding the default hover behavior.
Note that you should also include template bindings for all the other properties you want to be styled (Background, Foreground etc.).

XAML "The member `isChecked` is not recognized or accessable" error for a RadioButton style trigger

I have two RadioButtons that I'd like to change the text on based on their IsChecked state, but Visual Studio is telling me IsChecked and Content aren't recognized/accessable. The below code is the same for both buttons.
<RadioButton GroupName="{Binding CommunicatingGroupName}" IsChecked="{Binding IsCommunicating}" IsEnabled="{Binding IsActive}" FontSize="11" TextOptions.TextFormattingMode="Display" Content="ACTIVE" >
<RadioButton.Style>
<Style TargetType="{StaticResource ButtonBlue}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Content" Value="ACTIVE" />
</Trigger>
<Trigger Property="IsChecked" Value="false">
<Setter Property="Content" Value="STANDBY" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Content" Value="ACTIVE" />
</Trigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
I have ToggleButtons elsewhere in the file that work with the same <Style.Triggers> elements, and as far as I know should work the same way for these RadioButtons. Am I missing something specific to RadioButtons? I've rebuilt, restarted VS, etc. and the errors persist.
Look at this line:
<Style TargetType="{StaticResource ButtonBlue}">
You set target type to something that looks like style. Probably you tried to write something like this:
<Style TargetType="{x:Type RadioButton}" BasedOn="{StaticResource ButtonBlue}">

using MouseOver in StackPanel WPF

I have just started learning WPF and trying to hide a StackPanel during MouseOver. Below is the code that I use. I can only see the Panel flickering when mouse is placed on it but, it doesn't hide completely. Am I missing something here? Thanks in advance.
<Style x:Key="myStyle" TargetType="{x:Type StackPanel}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Visibility" Value="Hidden" />
</Trigger>
<Trigger Property="IsMouseOver" Value="false">
<Setter Property="Visibility" Value="Visible" />
</Trigger>
</Style.Triggers>
</Style>
Stackpanel:
<StackPanel Style="{StaticResource myStyle}">
// Child controls
</StackPanel>
When the StackPanel is hidden, the IsMouseOver property toggles to false, which makes the StackPanel visible again.
You might set the Opacity property instead of Visibility:
<Style x:Key="myStyle" TargetType="{x:Type StackPanel}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Opacity" Value="1" />
</Trigger>
</Style.Triggers>
</Style>
Or, as pointed out in the other answer, declare just one Trigger for IsMouseOver == true:
<Style x:Key="myStyle" TargetType="{x:Type StackPanel}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0" />
</Trigger>
</Style.Triggers>
</Style>
Clemens has already answered your question, but just FYI when you are triggering on a Boolean value, you don't need a trigger for both states. Just set a single trigger for the true or false state, then when the state no longer applies the properties that were changed by the setters in the trigger will revert back to their previous values. This will cut down on the amount of XAML you need to write.

Button IsEnabled Trigger does not work

I have a Button and its Style:
<Button Name="MyBtn" Style="{StaticResource ButtonEnabledStyle}"
IsEnabled="False" Opacity="1" />
<Style x:Key="ButtonEnabledStyle" TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True" >
<Setter Property="Opacity" Value="0.1" />
</Trigger>
</Style.Triggers>
</Style>
But when I enable the Button (MyBtn.IsEnabled = true) it does not change its Opacity. Why? How can I solve this problem? Thanks.
A local value set on the element (Opacity="1" in your code) will always take precedence over a style or style trigger value. Please have a look at Dependency Property Setting Precedence List.
An easy fix is to set the default value on the style instead:
<Style x:Key="ButtonEnabledStyle" TargetType="Button">
<Setter Property="Opacity" Value="1.0" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True" >
<Setter Property="Opacity" Value="0.1" />
</Trigger>
</Style.Triggers>
</Style>

Change a button's content in a style?

I'm trying to do something similar to this:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Button>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Content"
Value="No mouse over" />
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Content">
<Setter.Value>
<CheckBox Content="Mouse is over" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</Window>
However, I get a run-time XamlParseException with a message of:
Cannot add content of type
'System.Windows.Controls.CheckBox' to
an object of type 'System.Object'.
Error at object
'System.Windows.Controls.CheckBox
I'm actually trying to draw different icons for the button's content depending on external conditions. So I'm actually trying to use a DataTrigger, but the example above simplifies the problem. Any ideas?
The actual error is occurring because Visuals can not be directly set as a Setter value.
You can get the behavior you are looking for though, by setting the ContentTemplate using a DataTemplate, or by creating your content as a resource, either specific to the button or located elsewhere.
<Button>
<Button.Resources>
<CheckBox x:Key="Local_MouseOverContent" Content="Mouse is over" />
</Button.Resources>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Content" Value="No mouse over" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Content"
Value="{StaticResource Local_MouseOverContent}" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Content" Value="No mouse over" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="Button">
<CheckBox Content="Mouse is over" />
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
REMARK! Exactly your example works in .NET Framework 4 without any Changes !!!!
<Button>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Content"
Value="No mouse over" />
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Content">
<Setter.Value>
<CheckBox Content="Mouse is over" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
If you are making a generic style to be used by buttons all around your app, you will get visual tree conflicts using the approach where the image is a resource. So the template is your only choice in that case.
WARNING: This may not be the best or correct way to do it. Make sure you read the other answers on this page as well.
Pretty sure you'd want to use a control template in this sort of situation. Something like:
<style>
<Setter Property="Content">
<Setter.Value>
<ControlTemplate>
<Image Img="something.jpg" />
</ControlTemplate>
</Setter.Value>
</Setter>
</style>
And add a control template in the trigger for the on-hover.
Here's a good link

Categories