Style breaks when x:Key is added - wpf

Under <Window.Resources>, I have the following style defined:
<Style TargetType="TextBox">
<Setter Property="Height" Value="22" />
<Setter Property="Width" Value="125" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="WhiteSmoke" />
</Style>
It works fine until I needed to inherit the style on another style
<Style BasedOn="{StaticResource TextBoxStyle}" TargetType="{x:Type PasswordBox}">
Which means I need to add the x:Key=TextBoxStyle to the Text box style above.
But when I do this, the styling for the text box breaks altogether.
I tried doing the same to Button styling, and the same thing happens, where the style will break if I add a key to it.
The only solution I thought of is to individually add the style to the elements, but that is what I am trying not to do.

No, you do not need to add x:Key to reference it:
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type PasswordBox}">

Well to provide a better understandability and maintainance, I would prefer the following approach. IMHO, another programmer could get better into the code, if the implicities are reduced to a minimum.
<Style x:Key="BasicTextBoxStyle" TargetType="{x:Type TextBox}">
<!--some settings here-->
</Style>
<!--Declare BasicTextBoxStyle as default style for TextBoxes-->
<Style BasedOn="{StaticResource BasicTextBoxStyle}" TargetType="{x:Type TextBox}"/>
<!--Create some special style based on the basic style-->
<Style BasedOn="{StaticResource BasicTextBoxStyle}" TargetType="{x:Type PasswordBox}">
<!--some more specific settings-->
</Style>
Just my two cents...

Related

Wpf - Create a Style in a resource dictionary that sets properties of children of a grid [duplicate]

Is it possible to define a ResourceDictionary in a Style?
For example, suppose I wanted to have two different Styles for StackPanels and in one I want all the buttons to be blue and the other I want them to be red. Is this possible?
Something like
<Style x:Key="RedButtonsPanel" TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="StackPanel.Resources">
<Setter.Value>
<ResourceDictionary>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red" />
</Style>
</ResourceDictionary>
</Setter.Value>
</Setter>
</Style>
The above code fails with an error about the Property value of a Setter cannot be null (even though it's obviously not null).
I can do something like
<ResourceDictionary x:Key="RedButtons">
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="100" />
<Setter Property="Background" Value="Red" />
</Style>
</ResourceDictionary>
<StackPanel Resources={StaticResource RedButtons} />
However I was wondering if there was a way to merge the ResourceDictionary into the style.
Try adding the Style(s) for each TargetType to the DockPanel Style.Resources.
I did something similar with a DockPanel Style. Wanted all Buttons or Separators added to the DockPanel to get styled in a consistent manner.
Here's a sample:
<Style x:Key="DockPanelToolBarStyle" TargetType="{x:Type DockPanel}">
<Style.Resources>
<Style TargetType="Button" BasedOn="{StaticResource ButtonToolBarStyle}" />
<Style TargetType="Separator" BasedOn="{StaticResource SeparatorToolBarStyle}" />
</Style.Resources>
<Setter Property="Height" Value="45"/>
<Setter Property="Background" Value="{StaticResource ToolBarBrush}"/>
</Style>
StackPanel.Resources is not a DependencyProperty and therefore I don't believe you will be able to set that property within the style.

How to Change the Style on AvalonEdit CodeCompletion Window?

I'm trying to figure out how to change the style of the AvalonEdit CodeCompletion window. However, I can't figure out the right combination of xaml style target/properties to change it. The main thing I'd like to do is get rid of the border, but maybe some additional changes as well.
Here is the xaml I've tried. None of it is affecting the UI.
xmlns:ae="clr-namespace:ICSharpCode.AvalonEdit.CodeCompletion;assembly=ICSharpCode.AvalonEdit"
<Style TargetType="{x:Type ae:CompletionWindow}">
<Setter Property="WindowStyle" Value="None" />
</Style>
<Style TargetType="{x:Type ae:CompletionWindowBase}">
<Setter Property="WindowStyle" Value="None" />
</Style>
<Style TargetType="{x:Type ae:CompletionListBox}">
<Setter Property="Background" Value="Red" />
</Style>
<Style TargetType="{x:Type ae:CompletionList}">
<Setter Property="Background" Value="Orange" />
</Style>
Use this style to remove border on window:
<Style TargetType="{x:Type avalonEdit:CompletionWindow}">
<Setter Property="WindowStyle" Value="None"></Setter>
<Setter Property="ResizeMode" Value="NoResize"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
</Style>
To make the styles affect the UI, you can put them in a resource dictionary xaml and parse that with (ResourceDictionary)XamlReader.Parse(ResourcesAsXaml).
Then assign the ResourceDictionary to the Resources property of the CompletionWindow.

Code reusability in Styles

I have a style element which has minor edits and mostly repeated. How do i make it more generic - so setter properties are set within based on value versus repeating the code twice
<ResourceDictionary>
<Style x:Key="TextBlockStyleEnvironment" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="5,4,0,0" />
<Setter Property="FontSize" Value="8" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style x:Key="TextBlockStyleLocation" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="5,4,0,0" />
<Setter Property="FontSize" Value="10" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ResourceDictionary>
As you see from the code all setter properties are same except Margin and FontSize. Also attached is the screenshot of it on rendering.
Please note - want to keep this self contained within a Style and not have declare at local level in XAML when this being consumed.
Possible values of Env can be Dev,QA,Prod and possible values of location can be TK, LN
Consuming in XAML snippet as follows:
<Grid DataContext="{....}">
<StackPanel>
<TextBlock Text="{Binding Environment}" Style="{StaticResource TextBlockStyleEnvironment}"/>
<TextBlock Text="{Binding Location}" Style="{StaticResource TextBlockStyleLocation}"/>
You can use style inheritance:
<ResourceDictionary>
<Style x:Key="BaseTextBlockStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="5,4,0,0" />
<Setter Property="FontSize" Value="8" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style x:Key="TextBlockStyleEnvironment" BasedOn="{StaticResource BaseTextBlockStyle}" TargetType="{x:Type TextBlock}" />
<Style x:Key="TextBlockStyleLocation" BasedOn="{StaticResource BaseTextBlockStyle}" TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="10" />
</Style>
</ResourceDictionary>
Additionally you can create attached properties and bind to those from within your control templates. This gives you the flexibility of not having to create hundreds of styles just because something minute needs to be different.
A good example of that is a button that has an image. When the mouse is over the image, the image needs to change. Typically you'd have to create a new control template/style for each button that implements that behavior. However, if you create two attached properties - NormalStateImageSource and MosueOverImageSource, you can bind to those in your control template. This allows you to have a single full blown style for the button, and later to declare individual styles for other buttons that only change the values of these attached properties.
There are few techniques in WPF world.
First, if styles are same type, it's possible to use BasedOn attribute:
<Style x:Key="GenericTextBlockStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="5,4,0,0" />
<Setter Property="FontSize" Value="8" />
</Style>
<Style x:Key="TextBlockStyleEnvironment"
BasedOn="{StaticResource GenericTextBlockStyle}"
TargetType="{x:Type TextBlock}">
</Style>
However the BasedOn attribute can get really messy sometimes. It's also possible to do it this way, which will work for elements that are not the same type:
<Thickness x:Key="LeftBorderMargin" Top="10" />
<Style x:Key="TextBlockStyleEnvironment" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="{StaticResource LeftBorderMargin}" />
</Style>
It's common practice to refactor all the colors / margins out from the Style element, for reusability.

Removing Selected State of all templates (Global Style)

I need to remove the selected state (effect) or whatever it is called from every control in my interface. You know the black dashed line...
What are the ways for it to be done?
P.S. Is it normal for a fully customized XAML page to use 30MB RAM?
Thanks in advance.
That is controls by the FocusVisualStyle of the associated control. Unfortunately, you cannot disable that globally for all controls using a single Style or setting. Instead, you'd have to individually turn it off for every control type.
For example, you can include the following styles in your Application.Resources to turn it off for the specified controls:
<Style TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
</Style>
<Style TargetType="RepeatButton">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
</Style>
<Style TargetType="ToggleButton">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
</Style>
<Style TargetType="TreeViewItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
</Style>
<!-- ETC -->
But keep in mind, that if you use the Style property on any of the controls or if you have any other implicit styles defined then those will prevent the styles above from being applied.
Or as Rachel point out, you could do this:
<Style x:Key="FrameworkElementStyleKey" TargetType="FrameworkElement">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
</Style>
<Style TargetType="Button" BasedOn="{StaticResource FrameworkElementStyleKey}" />
<Style TargetType="RepeatButton" BasedOn="{StaticResource FrameworkElementStyleKey}" />
<Style TargetType="ToggleButton" BasedOn="{StaticResource FrameworkElementStyleKey}" />
<Style TargetType="TreeViewItem" BasedOn="{StaticResource FrameworkElementStyleKey}" />
<!-- ETC -->
Functionally, both approaches above have the same effect.

How to base a style on another style in a resource dictionary?

I have a theme that is applied to all buttons in a resource dictionary. Now I want to add a trigger to the button while inheriting the style changes from the dictionary. I tried the following code, but it says that the control cannot be found. How can I fix it ?
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Theme.xaml"/>
</ResourceDictionary.MergedDictionaries>
<conv:ErrorContentConverter x:Key="ErrorContentConverter" />
<Style x:Key="ValidTrigger"
TargetType="Control" BasedOn="{StaticResource {x:Type Control}}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsValid}" Value="False">
<Setter Property="IsEnabled" Value="false" />
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</UserControl.Resources>
The base template:
<Style TargetType="{x:Type Button}" BasedOn="{x:Null}">
<Setter Property="FocusVisualStyle"
Value="{DynamicResource NuclearButtonFocusVisual}" />
<Setter Property="Foreground" Value="#FF042271" />
<Setter Property="FontFamily" Value="Trebuchet MS" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Padding" Value="3" />
<Setter Property="Template" Value="{DynamicResource ButtonTemplate}" />
</Style>
One trick I've used in the past: in your ResourceDictionary that defines blanket styles for your application, add an x:Key to the style you'd like to inherit from, like so:
<Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
<!-- your style here -->
</Style>
To apply this style to all controls of the specified type (Button in this example) without having to explicitly set the Style attribute of every Button, add another style that's BasedOn this style, but doesn't have a key:
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource ButtonStyle}" />
Using this method, all Buttons in your application will automatically inherit your custom style, but you can still create additional styles BasedOn the ButtonStyle entry and avoid blowing away all of your custom styling.
Give your base Style a name, say FooStyle.
In the example you gave, modify the TargetType and BasedOn to look as follows:
<Style x:Key="ValidTrigger"
TargetType="{x:Type Control}" BasedOn="{StaticResource {x:Type Control}}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsValid}" Value="False">
<Setter Property="IsEnabled" Value="false" />
</DataTrigger>
</Style.Triggers>
</Style>
I think there is no base style defined for "control" so your
BasedOn="{StaticResource {x:Type Control}}" part won't find anything.
You probably want to change
<Style x:Key="ValidTrigger" TargetType="Control" BasedOn="{StaticResource {x:Type Control}}" >
to
<Style x:Key="ValidTrigger" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" >

Resources