Add ErrorTemplate to a MahApp control without overwriting its default style - c#

I am using MahApps and working on implementing validation for TextBoxes. MahApps provides some nice properties in TextBoxes, as Controls:TextBoxHelper.Watermark and Controls:TextBoxHelper.ClearTextButton. I am writing an ErrorTemplate using my style but I overwrite the default template of the TextBox and lose those Metro properties. How can I achieve my goal without losing the template:
<Style TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate" Value="{DynamicResource ErrorToolTipTemplate}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>

You should define your new style based on existing to keep everything it has. I guess in case of MahApps it will be MetroTextBox:
<Style TargetType="TextBox" BasedOn="{StaticResource MetroTextBox}">
<!-- your properties go here -->
</Style>

The BasedOn is the key to success. However, it's likely, that you're using MahApps controls not in just one place. Therefore, try to make your style more generic and avoid direct references to MetroTextBox resource in the BasedOn.
The more good looking XAML style would be like that:
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<!-- your properties go here -->
</Style>

Related

C# WPF Xaml: Globally set all text in a view to one color, and all backgrounds to another

Is there a way (using data binding or simply xaml) to set the background of all elements in a view to one color, and all text to another?
I know I can edit each element in the view one by one, but I I'd like to see if this is possible with settings at a global level. Kind of like how everything by default is set to black on white.
I guess what I'm asking is if there is a feature/setting of a WPF application that offers what I'm looking for, and/or what I should search to find an answer online.
My project isn't using anything but what visual studio offers when you create a WPF project, so I can't use a prism or mvvm light approach.
Thanks in advance for your answer!
Globally...or simply XAML...
if there is a feature/setting of a WPF application that offers what I'm looking for
In Application Resource add style like this:
<Style TargetType="Control">
<Setter Property="Background" Value ="Blue"/>
<Setter Property="Foreground" Value ="Red"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Background" Value ="Blue"/>
<Setter Property="Foreground" Value ="Red"/>
</Style>
Based on your target element you want to set background.
When you say "the background of all elements in a view" you should be more specific, If by 'element' you mean UIElement then there is no Background property in UIElement. If it means Control then not all UIElementsderive from Control (e.g. TextBlock) and finally if it means every UIElement derived type defined in your view that have a Background property, then you should add different styles for each type without setting the x:key to the YourView.Resources like this:
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Blue" />
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Blue" />
</Style>
...
</Window.Resources>
uses controls collection through which you can control all controls in WPF

General WPF Rendering Rules (Multiple styles on same target type)

Relating on this question (Multiple styles on same target type) i have another point concerning the general wpf styling rules.
As mentioned in one of the answers above, wpf applies the closest style definition to the control when no x:key is specified. (also applies to styles with the same key; given the fact that we have the same key here: the control type)
My question:
What if we have two same-named styles in different resource dictionaries that are both equal close and accessible to the control?
Compared to CSS you have two definitions for i.e. an a-element. In CSS same style properties are getting overriden by the last definition while different properties are merged into one logical style definition.
Does WPF behave the same or does it prefer one whole style-resource with all its properties while avoiding the other one completely?
And if the latter how does it decide to apply one or the other.
Update
dict1.xaml:
<ResourceDictionary>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="BorderBrush" Value="SomeValue1" />
<Setter Property="Background" Value="SomeValue2" />
<Setter Property="FontSize" Value="SomeValue3" />
</Style>
</ResourceDictionary>
dict2.xaml:
<ResourceDictionary>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="BorderBrush" Value="SomeValue4" />
<Setter Property="Foreground" Value="SomeValue5" />
</Style>
</ResourceDictionary>
SomeView.xaml:
...
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="path/dict1.xaml" />
<ResourceDictionary Source="path/dict2.xaml" />
</ResourceDictionary.MergedDictionaries>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="FontSize" Value="SomeValue6" />
</Style>
</Grid.Resources>
<Button /><!--THIS IS THE CONTROL THAT MATTERS-->
</Grid>
...
I think for FontSize its simple, it applies SomeValue6 because its the closest style definition. But what about BorderBrush. Both Dictionaries are equally close to the Button and are both accessible.
And What about Background and Foreground? Does it merge both style definitions to something like this:
<ResourceDictionary>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="BorderBrush" Value="SomeValue4" />
<Setter Property="Background" Value="SomeValue2" />
<Setter Property="Foreground" Value="SomeValue5" />
<Setter Property="FontSize" Value="SomeValue6" />
</Style>
</ResourceDictionary>
Of course the chaos is much bigger when you include cross-assembly dictionaries, that depend on each other and you are seeking where the actual style comes from.
This code example isn't working because of the merged dictionary and its hard to isolate the exact behavior because my actual application is really chaotic like I described.
So I want to know the official rules intended by Microsoft that should be basic for every developer. But I didnt find anything in the docs.

The Style object cannot affect the Style property of the object to which it applies

I have two styles
<Style x:Key="FontElemNivel1">
<Setter Property="TextElement.FontSize" Value="12"/>
<Setter Property="TextElement.FontFamily" Value="Tahoma"/>
<Setter Property="TextElement.FontWeight" Value="Bold"/>
</Style>
And this
<Style x:Key="ElementoNivel1" TargetType="TextBlock">
<Setter Property="Style" Value="{StaticResource FontElemNivel1}"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
If I try to use the second on an object like this
<TextBlock Text="Entidad" Style="{DynamicResource ElementoNivel1}"/>
The compiler throw this error:
Error 16 the Style object cannot affect the Style property of the object to which it applies.
Why this happens ?
How to implement it properly ?
<Style x:Key="ElementoNivel1" TargetType="TextBlock" BasedOn="{StaticResource FontElemNivel1}">
This should rectify an error. You tried to assign style to style.
For BasedOn to work FontElemNivel1 will need to target a Textblock.
If doesn't suit because FontElemNivel1 needs to be used for something other than textblocks then maybe this previously answered question will help:
XAML Combine Styles

Textbox style trigger with "IsReadOnly" not working

I've made an application resource with a style which should be triggered if the textbox has the "IsReadOnly" property. Looks like this:
<Application.Resources>
<Style TargetType="{x:Type TextBox}" >
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="True">
<Trigger.Setters>
<Setter Property="Background" Value="Black" />
</Trigger.Setters>
</Trigger>
</Style.Triggers>
</Style>
</Application.Resources>
However, the program doesn't react to this. It works when I use IsEnabled=True. However IsEnabled=False doesn't work either. So, question: Do the triggers only work if you check for "True"? And is IsReadOnly not supported at all? If so: How do I know which control properties are actually supported?
See an answer for this problem by following the provided link:
DataTrigger problem with textbox

Silverlight apply implicit style that sets other style

I have a TextBox Style with a Key defined in external resource dictionary file, then I'm trying to define a new implicit TextBox Style that sets "Keyed" style from resource dictionary, so basically I want to seet the style from resource dictionary as a default for TextBox, but I can't remove Key from there, because it is used by other code.
<ResourceDictionary Source="FileWithNiceTextBoxStyle.xaml"/>
<Style TargetType="TextBox">
<Setter Property="Style" Value="{StaticResource NiceTextBoxStyle}"/>
</Style>
However this doesn't work, and result in Visual Studio crash.
Use the BasedOn attribute:
<Style TargetType="TextBox" x:Key="GlobalTextBox">
<Setter Property="Background" Value="Pink"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource GlobalTextBox}"></Style>
...
<TextBox Text="I have pink background"/>

Categories

Resources