Finding the Content of a ContentPresenter and setting styles - c#

I couldn't find an appropriate topic for my problem. I have the following code.
<ContentPresenter x:Name="ContentPresenter"
VerticalAlignment="Center"
Width="Auto"/>
<TextBox x:Name="TextBlockFront" >
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=TextBlockFront, Path=IsFocused}" Value="true"/>
<Condition Binding="{Binding ElementName=ContentPresenter, Path=ContentProperty}" Value="ComboBox"/>
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Hidden"/>
<Setter Property="Text" Value="{Binding ElementName=ContentPresenter,Path=SelectedItem}"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
I want to get the clarification about the second condition of my MultiTrigger. I am relative new to WPF and I would appreciate any help in sorting out my doubt.
Expected behaviour:
when the TextBox is focused AND the ContentPresenter is ComboBox then I want to set the above properties. If the ContentPresenter is TextBox then I will set the Text property instead of SelectedItem

Related

ContentStringFormat never changes by Setter Property in DataTrigger

In my user control I want to have label displaying Text from resource depending on viewmodel property Location value and with different format.
I implemented it by defining DataTrigger for each Location value
<Style x:Key="LocationValueHelper" TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding Location}" Value="HomeViewModel">
<Setter Property="Content" Value="" />
<Setter Property="ContentStringFormat" Value="{}{0}???"/>
</DataTrigger>
<DataTrigger Binding="{Binding Location}" Value="FirstViewModel">
<Setter Property="ContentStringFormat" Value="{}{0}+++"/>
<Setter Property="Content" Value="{localization:LanguageResource ResourceKey=First}" />
</DataTrigger>
<DataTrigger Binding="{Binding Location}" Value="SecondViewModel">
<Setter Property="ContentStringFormat" Value="{}{0}---"/>
<Setter Property="Content" Value="{localization:LanguageResource ResourceKey=Second}" />
</DataTrigger>
<DataTrigger Binding="{Binding Location}" Value="ThirdViewModel">
<Setter Property="ContentStringFormat" Value="{}{0}***"/>
<Setter Property="Content" Value="{localization:LanguageResource ResourceKey=Third}" />
</DataTrigger>
</Style.Triggers>
</Style>
<Label Foreground="White" HorizontalAlignment="Center" FontSize="40" Style="{StaticResource LocationValueHelper}" />
The problem is that format never changes from the first one (???) - HomeViewModel selected first - although text changing works.
I have
Home???
First???
Second???
Third???
instead of
Home???
First+++
Second---
Third***
There are a lot of discussions, using Labels and ContentStringFormat does not work like expected or desired:
WPF StringFormat on Label Content
StringFormat VS ContentStringFormat
...
The reason seems to be the template based implementation under the hood, since the content also could contain other data than strings. To solve your problem, my proposal is to use a TextBlock, which works quite smooth like this:
<StackPanel>
<CheckBox IsChecked="{Binding MyFlag}"/>
<TextBlock HorizontalAlignment="Center" FontSize="40">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding MyFlag}" Value="False">
<Setter Property="Text" Value="{Binding Path=MyText, StringFormat='{}{0}+++'}" />
</DataTrigger>
<DataTrigger Binding="{Binding MyFlag}" Value="True">
<Setter Property="Text" Value="{Binding Path=MyText, StringFormat='{}{0}???'}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>

Is it possible to set a RowDefinition Resource to style all TextBlocks in that row?

I have a Grid with a number of TextBlocks.
I want to change the foreground of each TextBlock based on a boolean value in the associated ViewModel.
Each TextBlock in a row uses the same binding from VM to change, so I thought a good way to do it would be to set a Style with a Data Trigger on the GridRow.
I've tried using the following:
<Grid.RowDefinitions>
<RowDefinition Height="Auto">
<RowDefinition.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding TempWarning}" Value="True">
<Setter Property="Foreground" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RowDefinition.Resources>
</RowDefinition>
Then I declare the TextBlock like this:
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding CurrentTemp}" HorizontalAlignment="Right" Margin="5,0"/>
However, even though the TempWarning value is set to true, the TextBlock foreground is not updating.
Can anyone suggest why?
You should move the Style to <Grid.Resources>:
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding TempWarning}" Value="True">
<Setter Property="Foreground" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
...
</Grid>
An implicit resource in <RowDefinition.Resources> is not applied to an element in the Grid.
If you only want the Style to apply to a specific row, you could use a MultiDataTrigger that also binds to the Grid.Row attached property of the TextBlock itself:
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding TempWarning}" Value="True" />
<Condition Binding="{Binding Path=(Grid.Row),
RelativeSource={RelativeSource Self}}" Value="0" />
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="White"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>

Enabling TextBox with trigger

I want a Textbox to be disabled, except the user hovers with the mouse over it. But this does not seam to work, the Textbox is still not editable if I hover over it. (Yes I know that this is unusual.)
What I tried is:
<Border>
<TextBox Text="Hover to edit me!" IsEnabled="False" >
<TextBox.Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Border}, Path=IsMouseOver}" Value="True">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
<!-- this does not work either -->
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="True">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
<!-- neither did this -->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsEnabled" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Border>
I wonder if it is possible at all using a trigger?
This is because of the Dependency Property Value Precedence in WPF.
You need to set the IsEnabled property to false in the Style, so the trigger can override the value.
The local value has always a higher priority, so setting IsEnabled="False" directly in the text box will override any style or style trigger value.
Here is a working example:
<Border>
<TextBox Text="Text">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<DataTrigger
Binding="{Binding IsMouseOver,
RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}"
Value="True">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Border>

DataTrigger setter will not update property. Why?

XAML :
<RadioButton x:Name="RadioButtonA">
<RadioButton.Style>
<Style TargetType="RadioButton">
<Setter Property="IsChecked" Value="{Binding Path=RadioAValue}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CheckBoxA, Path=IsChecked}" Value="True">
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
C# Code behind
public bool RadioAValue
{
get
{
...
}
set
{
...
}
}
set section of RadioAvalue will not be called when CheckBoxA is checked.
Any reason why?
Problem in your code
You are setting the binding in Style Setter
<Setter Property="IsChecked" Value="{Binding Path=RadioAValue}" />
and on clicking the checkbox you have overwriting the Binding with the value False. Now there is no more Bindings over the element and it wont call the set anymore.
Also, if you try to bind it over the RadioButton itself instead of setters that will take more precedence and your Triggers won't work there.
Solution
I would recommend you to have Command binding over the Checkbox and update the value RadioAValue from your ViewModel
If you want conditional setter use MultiBinding, right now you block binding with already setted value
<Setter Property="IsChecked" Value="{Binding Path=RadioAValue}" />
Must be something like this (didn't test thought):
<RadioButton x:Name="YouRadioButton">
<RadioButton.Style>
<Style TargetType="RadioButton">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=CheckBoxA, Path=IsChecked}" Value="True"/>
<Condition Binding="{Binding RadioAValue}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="IsChecked" Value="True"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<DataTrigger Binding="{Binding ElementName=CheckBoxA, Path=IsChecked}" Value="False">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
<CheckBox x:Name="CheckBoxA"/>

Tooltip for Textbox with maxlength property

I want to make a tooltip for my TextBoxes in XAML, and i want do do this with styling in Xaml.
The Tooltip should display something like Enter up to x characters, with x equal to the MaxLength property of the textbox. I only want to display the tooltip if the MaxLength is set.
What i have now is something like:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Margin="0" Text="{Binding MaxLength, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBox}}, StringFormat='Enter up to {0} characters'}"/>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
The condition is working, so if there is a MaxLength set the tooltip is displayed. Only the binding inside the tooltip is not working.
Other stuff that i've tried is:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Content="{Binding MaxLength, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBox}}}" ContentStringFormat="{}Enter up to {0} characters"/>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
This gives the same problem as the option shown above, but i cant style the tooltip properly.
Another thing i've tried is:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip" Value="{Binding MaxLength, RelativeSource={RelativeSource Self}, StringFormat='Enter up to {0} characters'}"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
But this way the string formatting won't work.
Something i've tried before and that has worked was:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource Self}}"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Margin="0" Text="{Binding MaxLength ,StringFormat='Enter up to {0} characters'}"/>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
But this way the DataContext for the TextBox, and my other bindings dont work anymore.
Does anyone have a solution that (favorably) only includes XAML?
EDIT
While using a converter for MaxLength to the text Enter up to MaxLength characters it worked.
I used:
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True">
<Setter Property="ToolTip" Value="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource textBoxToolTipConverter}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
MultiDataTrigger, as name implies, is meant to be used with many conditions. You actually never used more than one. You can leverage of couple options:
Create style for textBox and within set default ToolTip to "Enter up to.." and in style trigger check whether MaxLength equals either null or 0, if so set ToolTip empty.
Bind ToolTip property to MaxLength and in converter assign value based on whether MaxLength is set
EDIT
<TextBox Text="Text" MaxLength="55">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=MaxLength,StringFormat='Enter up to {0} characters'}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=MaxLength}" Value="0">
<Setter Property="ToolTip" Value="{x:Null}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
This will display maxLength since ToolTip needs to have StringFormat set in diffrent way. I refer you to this post. All in all you end up being forced to create converter.
You can try this for the first code example.
Update added full style code for clarification.
<Style x:Key="ToolTipTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource StandardTextBox}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding MaxLength, RelativeSource={RelativeSource Self}, Converter={StaticResource valueLargerThanZero}}" Value="True"></Condition>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Margin="0" Text="{Binding DataContext.MaxLength, RelativeSource={RelativeSource Mode=Self}, StringFormat=Enter up to {0} characters}"/>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>

Categories