WPF Button Trigger change child Textblock Foreground XAML - wpf

I have this button in XAML:
<Button Style="{StaticResource HeadButton}">
<TextBlock Style="{StaticResource HeadButtonText}">Add flavor</TextBlock>
</Button>
And I need that when you hover over the button, the TextBlock Foreground property should change (I know I can use Content in the button but I'm doing it like this for another reason).
How can I achieve this?

You can bind to the foreground property of the button, and use triggers to modify it.
<Style x:Key="Test" TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
<Button Style="{StaticResource Test}">
<TextBlock Text="Click HERe" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}}"/>
</Button>

Here is a code example of what you're trying to achieve. Although may I note it's not best practice to place a TextBlock directly inside the button as the text field is already there, and for the TextBlock to use the text field rather than writing between the tags like HTML
<Button Name="btn">
<TextBlock Text="Add Flavor">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=btn, Path=IsMouseOver}" Value="True">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>

Related

WPF - Triggers on TextBox click

I'm trying to write a xaml piece that will set my TextBox's text whenever it gets / loses focus. Currently it looks like this :
<TextBox Name="TextBoxLogin" HorizontalAlignment="Left" Height="25" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="160">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsMouseCaptured" Value="True">
<Setter Property="Text" Value="test"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
But for some reason whenever I click it, the text doesn't change. I'd like to know why and what are my options to make it work. I also tried other properties like IsStylusCaptured and IsFocused, they didn't work either.
The issue is simple, you are setting the Text property in the first line :( Either set it in the STyle or don't set it :
<TextBox Name="TextBoxLogin" HorizontalAlignment="Left" Height="25" TextWrapping="Wrap" VerticalAlignment="Top" Width="160">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Text" Value = "TextHEre"/>
<Style.Triggers>
<Trigger Property="IsMouseCaptured" Value="True">
<Setter Property="Text" Value="test"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

Color Style Textblock

I have this textblock with default foreground color is white
<TextBlock Text="First Cmd" Grid.Row="0" TextAlignment="Center" Margin="4" TextWrapping="Wrap" Foreground="White" Style="{DynamicResource ABC}">
<TextBlock.InputBindings>
<MouseBinding Command="{Binding AAA}" MouseAction="LeftClick" />
</TextBlock.InputBindings>
</TextBlock>
When the mouse is over the textblock, the forground color must change in black, but this Style doesn't work. Why ?
<Style x:Key="ABC" TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property ="IsMouseOver" Value="True">
<Setter Property= "Foreground" Value="Black">
</Trigger>
</Style.Triggers>
</Style>
You set the Foreground for TextBlock locally, so the Trigger setter cannot override that. You need to use a Style setter to set the initial Foreground:
<Style x:Key="ABC" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="White"/>
<Style.Triggers>
<Trigger Property ="IsMouseOver" Value="True">
<Setter Property= "Foreground" Value="Black">
</Trigger>
</Style.Triggers>
</Style>
The Foreground="White" should be removed from the <TextBlock ....
Understand more about Dependency Property Value Precedence.

Editable WPF ListBox contains textbox

I want to have dynamic editable listbox in wpf application. I am using textbox inside listbox, and I am binding Observable collection to that listbox. Now, I want to make textbox editable on mouse click. So, user can make change to textbox and save new textbox text.
<ListBox Name="ListTwo" ItemsSource="{Binding CollectionUrl, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString}" IsEnabled="False" >
</TextBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You should use IsReadOnly property. In the trigger you should check IsFocused property.
In the following example, I changed foreground color to indicate which TextBox is in the edit mode.
Example:
<ListBox Name="ListTwo" ItemsSource="{Binding CollectionUrl, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString}" MinWidth="100">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="IsReadOnly" Value="False" />
</Trigger>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="IsReadOnly" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If you want to allow users save changes after edit value in the TextBox, you can add button and show in the actual editing row:
<ListBox Name="ListTwo" ItemsSource="{Binding CollectionUrl, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString}" MinWidth="100">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="IsReadOnly" Value="False" />
</Trigger>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="IsReadOnly" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Button Content="Save" Grid.Column="1" Command="{Binding SaveChanges}">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=TextBoxList, Path=IsFocused}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My approach to accessing the text box (which was proving a nightmare) was to use your save button approach and in the Button's Button_Click function I used sender to retrieve the Button's parent, cast to (in your case) Grid. Then you can use that to access the Grid's Children with .Children[0] being your TextBox.
Bit of a Kluge because your code has to 'know' the type of the parent and the index of the child TextBox but these will not change. If necessary the purists can iterate through the Children to identify the required child explicitly.
Hope this helps someone.

Style DataTrigger Setter in Button Content is invalid

<StackPanel>
<TextBox Text="" x:Name="input"/>
<Button Content="DataTrigger Before">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=input, Path=Text}" Value="1">
<Setter Property="Content" Value="Changed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
Style DataTrigger Setter in Button Content is invalid
Thanks
Your DataTrigger is not change the value of the Content property because you set it inside the Button declaration. So, once setted, it will never changed. To allow changing, you have to set the value inside the Style.
This will works (I've tried):
<StackPanel>
<TextBox Name="input"/>
<Button>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Content" Value="DataTrigger Before"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=input, Path=Text}" Value="1">
<Setter Property="Content" Value="Changed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>

Use a property trigger to change a property that already has a binding

How can I use a property trigger in a style (or another method) to change a property (ToolTip for example) that already has its value defined by a binding?
I have a simple button like so:
<Button Name="Button1" Style="{StaticResource ButtonStyle}"
ToolTip="{Binding Name}" >My Button</Button>
It has a binding on the tooltip to show the Name property of the class set as DataContext.
My problem is I want to show the Name when the button is enabled, but something else when it is disabled. I thought I could get around my problem with a style and a trigger like so:
<Style TargetType="Button" x:Key="ButtonStyle">
<Setter Property="ToolTipService.ShowOnDisabled" Value="True" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="ToolTip" Value="Disabled" />
</Trigger>
</Style.Triggers>
</Style>
But this doesn't work. If I removed the tooltip binding from the button then I do get the correct tooltip when the button is disabled. But it seems I can't have both a binding and a trigger on the same property.
I could get around it by adding another trigger like so:
<Trigger Property="IsEnabled" Value="true">
<Setter Property="ToolTip" Value="{Binding Name}" />
</Trigger>
But I would like to use the style for 4 or 5 buttons that will all have different bindings for the enabled ToolTip, but the same (fixed) tooltip when they are disabled.
Any suggestions?
The easiest solution to your problem is to create a button style that all of your buttons can use (_DisabledButtonToolTipStyle in the example below) and then define a unique style for each button that applies the enabled tool tip value. If the individual buttons always have a different tool tip value then I'd recommended simply embedding the style like below; however, if you wanted to reuse the enabled tool tip style you could easily define it in your resources and give it a key.
<Window.Resources>
<Style x:Key="_DisabledButtonToolTipStyle" TargetType="Button">
<Setter Property="ToolTipService.ShowOnDisabled" Value="True" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="ToolTip" Value="Disabled" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Button Name="Button1" Content="My Button">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource _DisabledButtonToolTipStyle}">
<Setter Property="ToolTip" Value="{Binding Name}" />
</Style>
</Button.Style>
</Button>
</Grid>
Your problem has nothing to do with binding, the problem is that properties you set directly on the element override the properties set in a style, for example:
Given the style
<Style TargetType="Button">
<Setter Property="Background" Value="Blue"/>
</Style>
And those two buttons:
<Button Content="1st"/>
<Button Content="2nd" Background="Red"/>
The first button will get its background from the style but the second overrides the style background.
You can get what you want with triggers but not using styles, you can use a DataTemplate like this (the TextBox and CheckBox are there for testing):
<ContentPresenter Content="{Binding}">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<StackPanel>
<TextBox Name="edt" Text="Tooltip text"/>
<Button Name="btn" Content="x"
ToolTip="{Binding ElementName=edt, Path=Text}"
ToolTipService.ShowOnDisabled="True"/>
<CheckBox Content="Enabled"
IsChecked="{Binding ElementName=btn, Path=IsEnabled}"/>
</StackPanel>
<DataTemplate.Triggers>
<Trigger SourceName="btn" Property="IsEnabled" Value="False">
<Setter TargetName="btn" Property="ToolTip" Value="Disabled"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>

Resources