Here is the xaml that I am working on:
<TextBlock Text="{Binding Title}" Margin="10,0,0,0" VerticalAlignment="Center">
<TextBlock.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Margin" Value="0" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Resources>
</TextBlock>
When text = "" I want to clear up the margin. But somehow it does not work.
You must move Margin="10,0,0,0" from TextBlock to setter of Style:
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="10,0,0,0" />
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Margin" Value="0" />
</Trigger>
</Style.Triggers>
</Style>
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
Related
I have a listview bound to an Observable collection, the listview has properties that most of them will use the same trigger.
is it possible to define the trigger once in the resource section and just refer to it once needed by the properties ?
so far i come to this :
<Style TargetType="TextBlock" x:Key="Pstyle">
<Setter Property="Text" Value="Testing"/>
<Style.Triggers>
<DataTrigger Binding="{Binding P1}" Value="Testing">
<Setter Property="Foreground" Value="DarkGreen"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
and in the listview member i just apply the defined style to the propertie P1
Style="{DynamicResource Pstyle}"
but how to apply the same defined trigger for let say P2, P3, P4...
Since you want to put your trigger logic on the content of the TextBlock, in my opinion you should use a Trigger targeting Text property, instead of a DataTrigger.
Check out this sample code:
<Style TargetType="TextBlock" x:Key="Pstyle">
<Style.Triggers>
<Trigger Property="Text" Value="Testing">
<Setter Property="Foreground" Value="DarkGreen"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
<TextBlock Name="MyTextBlock1" Text="MyTextBlock1Text" Style="{StaticResource Pstyle}"/>
<TextBlock Name="MyTextBlock2" Text="MyTextBlock2Text" Style="{StaticResource Pstyle}"/>
<TextBlock Name="MyTextBlock3" Text="MyTextBlock3Text" Style="{StaticResource Pstyle}"/>
as you can see there is only one single style applied to different Textblocks.
Then you should adapt this to your listview.
I'm new to WPF styling and I cannot make next thing to work:
I've got a custom checkbox style with another checkbox in it. I need parent "IsChecked" value to change as "contolCheckBox" child in ControlTemplate changes.
Tryed different triggers but can't get to parent property.
For now I've got next xaml code:
<Style x:Key="CustomCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="Height" Value="27" />
<Setter Property="Foreground" Value="#FFBABAC7" />
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<CheckBox x:Name="contolCheckBox" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<ContentPresenter HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsChecked" Value="{Binding IsChecked, ElementName=contolCheckBox}"/>
<!---->
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Foreground" Value="#FF29E200"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Foreground" Value="Firebrick"/>
</Trigger>
</Style.Triggers>
</Style>
"IsChecked" value of control doesn`t changes.
What am I doing wrong?
Binding ElementName=contolCheckBox, Path=IsChecked
not working too.
I don't think controlCheckBox is within the name scope since it's declared within the ControlTemplate. So your binding isn't working. Instead, invert your binding and bind from the bottom up. What you're looking for in a sitation like this is template binding. Try this in yourControlTemplate ..
<CheckBox x:Name="contolCheckBox" HorizontalAlignment="Right" VerticalAlignment="Center"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked, Mode=TwoWay}" />
Note the RelativeSoucebinding. This indicates that I want to bind to the parent of the template. This is the common way to bind underlying ControlTemplate controls to parent properties.
I have multiple datatriggers of the form:
<Style x:Key="VerifyCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="Height" Value="14" />
<Setter Property="FontSize" Value="12" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=PrimaryInsuranceCompany, Path=(Validation.HasError)}" Value="True">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="IsChecked" Value="False" />
</DataTrigger>
The IsEnabled property on the CheckBox is set correctly. However, the IsChecked property does not get unchecked if it had been manually checked in the first place.
Can IsChecked be unchecked from a Setter?
Edit#1
To complicate matters a bit more, the checkbox is bound to a property in my viewmodel as:
<CheckBox
Style="{StaticResource VerifyCheckBox}"
IsChecked="{Binding PrimaryInsurance.SelectedInsurance.Verify}"
Content="Verify" HorizontalAlignment="Left" Margin="789,92,0,676" Width="46" />
And there are multiple DataTrigger s in the Style.Triggers each checking a different element on the UI. In short, the UI has all the data validation. For instance, the element named above, PrimaryInsuranceCompany is:
<wc:AutoFilteredComboBox
Name="PrimaryInsuranceCompany"
IsEnabled="{Binding PrimaryInsurance.Enabled}"
ItemsSource="{Binding PrimaryInsurance.AllCompanies}"
ItemTemplate="{StaticResource CompanyTemplate}"
IsEditable="True"
IsCaseSensitive="False"
IsTextSearchEnabled="True"
TextSearch.TextPath="Companyname"
Text="{Binding PrimaryInsurance.NewCompanyName, UpdateSourceTrigger=PropertyChanged}"
theFilter="{Binding PrimaryInsurance.TheFilter}"
SelectedItem="{Binding PrimaryInsurance.SelectedInsurance.Company}"
h:ComboBoxRegexValidator.RegexText="{x:Static h:RegexLibrary.NonEmptyRegex}"
HorizontalAlignment="Left" Margin="590,138,0,0" VerticalAlignment="Top" Width="363" />
So with the combobox element in particular, I was trying to avoid duplicating the validation process in the view model since it is already being done directly in the view. Can this be done?
This quite often causes a confusion. You might want to read this: https://msdn.microsoft.com/en-us/library/vstudio/ms743230%28v=vs.100%29.aspx.
Basically, dependency properties in wpf might be set in different places: locally (IsChecked=True), in style, in trigger, and so on. When property is set in multiple places, specific resolution order is used to resolve the conflict. Here is an example:
<Window.Resources>
<Style x:Key="VerifyCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="Height" Value="14" />
<Setter Property="FontSize" Value="12" />
<Style.Triggers>
<DataTrigger Binding="{Binding TestValue}" Value="True">
<Setter Property="IsChecked" Value="False" />
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<CheckBox Content="Hey there" IsChecked="True" Style="{StaticResource VerifyCheckBox}" />
Here we set IsChecked in two places: locally (IsChecked=True) and in trigger. Local value has higher priority and because of that, when TestValue will become true checkbox will not be unchecked. However we did not set IsEnabled locally, so it will have it's value from trigger. Note that if we did set IsEnabled=True locally, trigger would have no effect at all.
Now let's try like this:
<Window.Resources>
<Style x:Key="VerifyCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="Height" Value="14" />
<Setter Property="FontSize" Value="12" />
<Setter Property="IsChecked" Value="True"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding TestValue}" Value="True">
<Setter Property="IsChecked" Value="False" />
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<CheckBox Content="Hey there" Style="{StaticResource VerifyCheckBox}" />
We moved IsChecked initial setter in style and now it works as expected, because trigger has priority over values in style setter.
Update: user clicking does not change behavior above. So, if you have local IsChecked=True, then user clicked twice, then TestValue becomes true - it will not be unchecked. And if you do the same but initialize IsChecked=True in style setter - it will be unchecked.
First, let me say I've been working with WPF for about a week. I want to style a TextBox so that when it is disable, it is cleared. This article explained how to do it, however I'm confused on how to set the generic style as a resource so that every TextBox can bind to a different property without repeating the style for each TextBox.
<Window.Resources>
<Style TargetType="{x:Type TextBox}" x:Key="style1">
<Setter Property="Text" Value="{What do I really put here?}" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Text" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
....
<TextBox Style="{StaticResource style1}" Text="{Binding SomeProperty}"/>
Thanks!
You won't be able to use the Text property like that. Setting the Text property explicitly on any TextBox that has that style will override the Text setter in the trigger (like you noticed).
If you only need the TextBox to be cleared and not the property it is binding to, then a workaround is to use an attached property (or Tag) for the text which you bind Text to in the Style.
Example..
<Style TargetType="{x:Type TextBox}" x:Key="style1">
<Setter Property="Text" Value="{Binding RelativeSource={RelativeSource Self},
Path=Tag}"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Text" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
Then a TextBox can use this Style like
<TextBox Style="{StaticResource style1}" Tag="{Binding SomeProperty}" />
I am going crazy here! What am I missing and why it is not styling anything:
<Style x:Key="textBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
<TextBox Width="100" Style="{StaticResource textBoxStyle}" Height="20" Background="Yellow" ></TextBox>
The above code does not do anything. It does not highlight the TextBox control!
This occurs because local values override style values. (Properties set directly on an element have very high precedence.) You are setting Background directly on the TextBox, so WPF is going, "Well, he normally wants textBoxStyle backgrounds to be Red when focused, but for this particular TextBox, he's said he specifically wants Background to be Yellow, so Yellow it is."
So the fix is to move the Yellow background to be part of the Style:
<Style x:Key="textBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Yellow" />
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
and remove it from the TextBox:
<TextBox Width="100" Style="{StaticResource textBoxStyle}" Height="20" />
Define your Style before the TextBox or use DynamicResource instead of StaticResource