Conditional Tooltip Based On Checkbox WPF - c#

I've got a checkbox and a button in my WPF MVVM app. If the checkbox is checked I want a tooltip on the button that says "x" and if it's unchecked the tooltip should say "y".
Anyone know the best way to do this? I think it could be done with a separate property in my view model, but maybe there's an easier way to do this in just the xaml?
Thanks in advance.

You could use a Style with a DataTrigger that binds to the IsChecked property of the CheckBox:
<CheckBox x:Name="chk" Content="CheckBox" />
<Button Content="Button">
<Button.Style>
<Style TargetType="Button">
<Setter Property="ToolTip" Value="y" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=chk}" Value="True">
<Setter Property="ToolTip" Value="x" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>

Related

DataTrigger to a control's Validation.HasError

I have a user control which uses the INotifyDataErrorInfo interface and it turns red when it has errors, inside of this user control I put a TextBlock and the following DataTrigger doesn't seem to work:
<TextBlock Text="{Binding DurationText}"
Grid.Row="1">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ActivityUserControl, Path=(Validation.HasError)}"
Value="True">
<Setter Property="Foreground"
Value="White">
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
I made sure that the x:Name of my user control is correct (ActivityUserControl), the user control itself turns red when it has errors but the TextBlock's DataTrigger doesn't work (text stays black).
Your should set the Value of the DataTrigger to begin with:
<DataTrigger Binding="{Binding ElementName=ActivityUserControl, Path=(Validation.HasError)}"
Value="True">
...
You should also make sure that the ActivityUserControl is in the same namescope as the TextBlock and that it acually contains some validation errors.
You can solve the namescope issue by binding to the parent UserControl using the RelativeSource property:
Binding="{Binding Path=(Validation.HasError),
RelativeSource={RelativeSource AncestorType=UserControl}}"

fire event only from user request

Is the any way to make Checked and Unchecked only fire when button clicked by user?
IsChecked is bound to Playing property. This value may change from background (not by user). So it causes Checked and Unchecked events to fire again and conflict with other things.
When ever I try to write code to fix this it becomes real mess. Thanks for your help.
<ToggleButton x:Name="TogglePlay" Width="90"
Style="{DynamicResource TogglePlay}"
IsChecked="{Binding SessionData.Playing}"
Checked="TogglePlay_Checked" Unchecked="TogglePlay_OnUnchecked"/>
<StackPanel.Resources>
<Style x:Key="TogglePlay" TargetType="ToggleButton">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked , ElementName=TogglePlay}" Value="False">
<Setter Property="Content" Value="Play" />
</DataTrigger>
<DataTrigger Binding="{Binding IsChecked , ElementName=TogglePlay}" Value="True">
<Setter Property="Content" Value="Pause" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
You can try to use binding mode "OneWayToSource"

WPF Style Triggers for DataTemplates

I would like to set Triggers for the controls in a DataTemplate. Whenever I set a property of the control within the DataTemplate, it seems not working. However, If do not set the property within the TextBlock inside the DataTemplate, then I can see the effect of Trigger in the style (it works). I am not sure whether using Style Triggers with DataTemplate is good or not! The XAML is below;
<Grid>
<Grid.Resources>
<Style TargetType="TextBlock" x:Key="BlockOf">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="ExtraBold" />
<Setter Property="FontSize" Value="22" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
...........
DataTemplate for the button,
<Button.ContentTemplate>
<DataTemplate DataType="Button">
<TextBlock Style="{DynamicResource BlockOf}" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"
FontStyle="Italic" FontSize="9"/>
</DataTemplate>
</Button.ContentTemplate>
I can see two problems here. First one is that current trigger will work only for TextBlock inside Button, not over whole Button. You can change that by using DataTrigger with RelativeSource binding. Second problem is that even when mouse is over TextBlock Style.Trigger cannot overwrite local value that you set against TextBlock so you need to bring default values as Setter into your Style. Check Dependency Property Setting Precedence List
<Style TargetType="TextBlock" x:Key="BlockOf">
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="FontSize" Value="9"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}, Path=IsMouseOver}" Value="True">
<Setter Property="FontWeight" Value="ExtraBold" />
<Setter Property="FontSize" Value="22" />
</DataTrigger>
</Style.Triggers>
</Style>
and then TextBlock simply
<TextBlock Style="{DynamicResource BlockOf}" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}" />

Trouble setting a DataTrigger in WPF

I have a ComboBox and a Button on my main view, and I want to apply a style to the button such that when the combobox index is set to 1, the button becomes visible (initially it's hidden). This is my XAML code:
<Grid>
<StackPanel Orientation="Vertical" Margin="10">
<ComboBox Name="comboBox"/>
<Button Name="myBtn" Content="Hello" Visibility="Hidden">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=comboBox, Path=SelectedIndex}" Value="1">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Grid>
Someone already asked a question about this here, and I'm doing pretty much the same thing, but it doesn't work, the button remains hidden even when the index is changed to 1. The comobox is initially being populated in the code behind with 2 items. Any help is appreciated.
The problem is that dependency property values set locally (like you've done with visibility) have a higher precedence then those set from a style trigger. As such, even when the trigger is hit, it won't override the value you've already set.
The simple solution is to instead set the default value in a style Setter:
<Button Name="myBtn" Content="Hello">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=comboBox, Path=SelectedIndex}" Value="1">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
And now your trigger will override the property value when it is hit.
While you're at it, you should have a look at this link that lists the precedence order for setting DP values.

Change property depending on property in other control - WPF

I want to use some kind of trigger to change a button in my window to IsEnabled = False when the textbox property Validation.HasErrors of my textbox is True.
Can I do this with Triggers of some kind on the Button?
If yes, some example would be nice!
You can do this by using a Style. If you want to tie it directly to the text box, you could do something like this:
<Style x:Key="DisabledOnErrors" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding (Validation.HasErrors)}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
<TextBox x:Name="myTextBox" />
<Button Style="{StaticResource DisabledOnErrors}"
DataContext="{Binding ElementName=myTextBox}" />
This works if the button is not already binding to the DataContext for other properties. In this case, the Style is reusable for other button and text box pairings.
Yes, you can do this with triggers, but because you are referring to another element, you must use a DataTrigger rather than a normal Trigger:
<Button>
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding (Validation.HasError), ElementName=tb}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Note you must use a Style rather than the Button.Triggers collection, because Button.Triggers can contain only EventTriggers.

Categories