How Textbox interacts with TextElement - wpf

I can write like this
<TextBox FontWeight="ExtraBold">
</TextBox>
And I can write like this
<TextBox>
<TextBox.Style>
<Style>
<Setter Property="TextElement.FontWeight" Value="ExtraBold"/>
</Style>
</TextBox.Style>
But i don't understand how TextBox interracts with TExtElement. For example TExtBlock has Inlines property. And MSDN says the following "PasswordBox, RichEditBox and TextBox don't support a text object model that's based on TextElement."
Who knows how it works?!

TextBox.Fontweight inherits from Control.Fontweight, whose Value is of Type System.Windows.Fontweight
TextElement.FontWeight is also of Type System.Windows.FontWeight.
You refer to this prop via a Style setter, so you can access the Property over another Class as well (as long the types match)
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="ComboBox.FontWeight"
Value="Black" />
</Style>
</TextBox.Style>
</TextBox>
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Control.FontWeight"
Value="Black" />
</Style>
</TextBox.Style>
</TextBox>
Are also valid.
Why this works, see below in Comment.

Related

How to use default style with datatriggers?

I have default styles set from MaterialDesignInXaml and when I try to add a datatrigger to the control it does not use that same style.
How do I still use the default style while having datatriggers?
<TextBox Margin="10" VerticalAlignment="Bottom" Padding="5" materialDesign:HintAssist.Hint="Search">
<TextBox.Style>
<Style BasedOn="{StaticResource MaterialDesignOutlinedTextBox}"> <!--Not Allowed to do this -->
<Setter Property="TextBox.Visibility" Value="Collapsed"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=SearchStyle, Path=SelectedItem.Tag}" Value="Search">
<Setter Property="Label.Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
You have to specify the exact TargetType for the Style that matches the base style.
[...] if you create a style with a TargetType property and base it on another style that also defines a TargetType property, the target type of the derived style must be the same as or be derived from the target type of the base style.
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource MaterialDesignOutlinedTextBox}">
In the source code, the MaterialDesignOutlinedTextBox style has a TextBox target type.

Why style targettype has to be rebinded back to the original properties?

I am referring to the code block here, on Data triggers
<Window x:Class="WpfTutorialSamples.Styles.StyleDataTriggerSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="StyleDataTriggerSample" Height="200" Width="200">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<CheckBox Name="cbSample" Content="Hello, world?" />
<TextBlock HorizontalAlignment="Center" Margin="0,20,0,0" FontSize="48">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="No" />
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cbSample, Path=IsChecked}" Value="True">
<Setter Property="Text" Value="Yes!" />
<Setter Property="Foreground" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Window>
To me, from programming language design point of view, the line <Style TargetType="TextBlock"> is completely unnecessary, because it is already nested inside the <TextBlock>, so of course whatever setter property should be applied to the TextBlock type. So why need the line <Style TargetType="TextBlock">?
Can <Style TargetType> be of other type except TextBlock?
So why need the line ?
A Style may be defined as a resource, i.e. not inline, and if doesn't have a TargetType specified, how is the XAML parser supposed to be able to parse it and set the properties specified by the setters? It can't. Or at least it doesn't.
Just because you can define a Style inline you are still creating an instance of the exact same class that may be used as a (global) resource and then setting a TargetType is indeed required.
Can be of other type except TextBlock?
No, apart from a type that is derived from TextBlock. If you specify another type you will get an exception at runtime when the BAML (the compiled XAML) is parsed.
You could use any class TextBlock derives from (for example FrameworkElement).
If you implement your own CustomizedTextBlock for example you are able to use styles defined for TextBlock in your project.
You find an example for this here.

How to apply StaticResource using Textbox.Style

I have a textbox using AddItemsTextBoxStyle (defined in resource dictionary), as below:
<TextBox x:Name="txtItems" Style="{StaticResource AddItemsTextBoxStyle}" />
However, if I want to apply DataTrigger to my textbox, then I can't use the self-closing tags format. Instead, I need to reformat my textbox to something like this:
<TextBox x:Name="txtItems">
<TextBox.Style>
<Style>
<Style.Triggers>
...
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Sorry if this sounds silly. But how can I apply "static resource" for my textbox by using "TextBox.Style" tag?
You can use the Style.BasedOn property to combine your pre defined Style and your Trigger like this:
<TextBox x:Name="txtItems">
<TextBox.Style>
<Style BasedOn="{StaticResource AddItemsTextBoxStyle}">
<Style.Triggers>
...
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

Conditional overwrite of style property

I'm trying to alter the background of a textbox if the value of the field contains a specified text. The problem that I encounter is that I already have a style applied to the field and I try to overwrite a property of the style like in the following example but with no success. Any ideas how could I achieve this?
<TextBox Grid.Column="1"
HorizontalAlignment="Right"
Text="{Binding CustomerType}" >
<TextBox.Style BasedOn="{DynamicResource SelectableTextStyle}">
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding CustomerType}" Value="Unknown">
<Setter Property="TextBox.Background" Value="Tomato"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Your style definition, as written should probably not even compile because you are using an attribute on a property element (the TextBox.Style tag).
Update your code so that the inner style definition has the 'BasedOn' attribute like so:
<TextBox.Style>
<Style TargetType="TextBox" BasedOn="{DynamicResource SelectableTextStyle}">
<Style.Triggers>
....
And everything will be gravy.

Apply default WPF style

I have a global style that sets all my TextBox styles, but in some cases I want to revert just the Foreground color to the original non-custom-style color. I tried using {TemplateBinding Foreground} inside the specific TextBoxes that I wanted to revert. It didn't end up being valid XAML and I'm not sure that's the right way anyhow.
Any ideas? Thanks.
There's a few ways this could be done. If you look at the Precedence List on the MSDN
then you can see that the Forground set in ways 1-8 will override the Foreground from a default style. The easiest way being just to set the local value in the TextBox.
<TextBox Foreground="Red" />
Another thing that you can do is use the 'BasedOn' property of styles to override the other versions. This does require giving a key value to your default style, but that can then be used to also apply the default like in this example:
<Style TargetType="{x:Type TextBox}"
x:Key="myTextBoxStyle">
<Setter Property="Foreground"
Value="Red" />
<Setter Property="FontWeight"
Value="Bold" />
</Style>
<!-- Style applies to all TextBoxes -->
<Style TargetType="{x:Type TextBox}"
BasedOn="{StaticResource myTextBoxStyle}" />
<TextBox Text="Hello">
<TextBox.Style>
<Style BasedOn="{StaticResource myTextBoxStyle}" TargetType="{x:Type TextBox}">
<Setter Property="Foreground"
Value="Blue" />
</Style>
</TextBox.Style>
</TextBox>
Edit:
In the case that the default style is applying a value and you want to revert it to the base value there are a few ways I can think of, off hand, to get this behavior. You can't, that I know of, bind back to the default theme value in a generic manner.
We can however do some other things. If we need the style to not apply some properties, we can set the style to {x:Null}, thus stopping the default style from applying. Or we can give the element it's own style that does not inherit from the base style and then re-apply only the setters that we need:
<TextBox Text="Hello" Style="{x:Null}" />
<TextBox Text="Hello">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="FontWeight"
Value="Bold" />
</Style>
</TextBox.Style>
</TextBox>
We could modify the default style so that the Foreground will only be set on certain conditions, such as the Tag being a certain value.
<Style TargetType="{x:Type TextBox}"
x:Key="myTextBoxStyle">
<Setter Property="FontWeight"
Value="Bold" />
<Style.Triggers>
<Trigger Property="Tag"
Value="ApplyForeground">
<Setter Property="Foreground"
Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
<TextBox Text="Hello" />
<TextBox Text="Hello" Tag="ApplyForeground" />

Resources