Set default padding on ComboBox dependent on IsEditable property - wpf

I have set all my TextBoxes and ComboBoxes to have a default Padding of "1,3". When a ComboxBox is editable, the padding looks identical to the TextBoxes. But when IsEditable is defaulted to false, the padding doesn't look the same.
In App.xaml I already have:
<Application.Resources>
<Style TargetType="TextBox">
<Setter Property="Padding" Value="1,3"/>
</Style>
<Style TargetType="ComboBox">
<Setter Property="Padding" Value="1,3"/>
</Style>
</Application.Resources>
In App.xaml, how can I set all ComboBoxes with an IsEditable="False" property to have Padding="6,3,5,3"?

You can use a trigger to change the padding based on the property (in your case IsEditable) of the ComboBox. To do this, style your ComboBox like this:
<Style TargetType="{x:Type ComboBox}">
<Setter Property="Padding" Value="1,3"/>
<Style.Triggers>
<Trigger Property="IsEditable" Value="False">
<Setter Property="Padding" Value="6,3,5,3"/>
</Trigger>
</Style.Triggers>
</Style>

This is a great opportunity to use a keyed style on all applicable ComboBoxes:
<Style TargetType="ComboBox" x:Key="EditableComboBoxStyle">
<Setter Property="IsEditable" Value="False"/>
<Setter Property="Padding" Value="6,3,5,3"/>
</Style>
Add this as a keyed resource in your App.xamland apply it like so:
<ComboBox Style={StaticResource EditableComboBoxStyle}"/>
This will override your default style for any ComboBox to which you apply it.

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.

Can't set style with TargetType Shape

I am trying to set the Shape.Stroke property for several shape types using a style in WPF.
<Style.Resources>
<Style TargetType="{x:Type Polyline}">
<Setter Property="Stroke" Value="White"/>
</Style>
<Style TargetType="{x:Type Path}">
<Setter Property="Stroke" Value="White"/>
</Style>
<Style TargetType="{x:Type Ellipse}">
<Setter Property="Stroke" Value="White"/>
</Style>
...
</Style.Resources>
It does not seem possible to just set the style for the base class Shape.
<Style.Resources>
<Style TargetType="{x:Type Shape}">
<Setter Property="Stroke" Value="White"/>
</Style>
</Style.Resources>
Is there no better way than the first option I listed?
When WPF searches for an implicit Style, it looks for a resource whose key matches the DefaultStyleKey of the element to be styled. The convention in WPF is that every control T overrides the DefaultStyleKey to be typeof(T). WPF will not attempt to fall back to the base type's style key if a match is not found.
Ellipse, for example, has an implied[1] default style key of typeof(Ellipse), so WPF will only attempt to resolve an implicit style with that key; a resource keyed on typeof(Shape) will not be applied.
If you want to use implicit styles, you will need to define an implicit Style per concrete type. However, those styles may inherit setters and triggers from a common base Style:
<Style x:Key="x" TargetType="{x:Type Shape}">
<Setter Property="Stroke" Value="Black"/>
</Style>
<Style TargetType="Ellipse" BasedOn="{StaticResource x}" />
<Style TargetType="Path" BasedOn="{StaticResource x}" />
<Style TargetType="Polyline" BasedOn="{StaticResource x}" />
Note that while implicit styles for base types will not be applied automatically, they are still compatible, and they can be applied explicitly:
<Style x:Key="StrokedShape" TargetType="{x:Type Shape}">
<Setter Property="Stroke" Value="Black"/>
</Style>
<!-- ... -->
<Ellipse Style="{StaticResource StrokedShape}" />
[1] Some WPF elements do not override DefaultStyleKey. Shape and its subclasses are among them. In such cases, WPF assumes the default convention.

change property of a group of buttons [duplicate]

I want to change the background of a MenuItem when the MenuItem is pressed.
<Style x:Key="{x:Type MenuItem}" TargetType="MenuItem">
<Style.Triggers>
<Trigger Property="MenuItem.IsPressed" Value="True">
<Setter Property="MenuItem.Background" Value="#FFE389" />
<Setter Property="MenuItem.BorderBrush" Value="#C2762B" />
</Trigger>
</Style.Triggers>
</Style>
I tried doing the above, but the trigger does not seem to work. Is the Trigger wrong?
Update: It works for the event IsMouseOver but IsPressed does not seem to work
Update 2: It works for TopLevelMenuItems but does not work for TopLevelMenuHeaderItems.
Try this...which does not preface the property names with MenuItem and modify your TargetType and x:Key syntax...
<Style x:Key="MyStyle" TargetType="{x:Type MenuItem}">
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#FFE389" />
<Setter Property="BorderBrush" Value="#C2762B" />
</Trigger>
</Style.Triggers>
</Style>
EDIT:
Based on your updates take a look at how a default MenuItem is constructed via XAML. This should get you where you need to go in providing styling for the varying parts of the MenuItem. Note the use of the Role property within the MenuItem style dealing with the headers and items at both the top level and sub level.

Shared styling in WPF

What if I wanted to make all TextBlock elements in UserControl, or section of a UserControl, have FontWeight="Bold" and TextAlignment="Right"? Is there some style I can set for TextBlock elements within a certain scope so I don't have to repeat all those attributes?
Yes, create a style with no x:Key and it will be applied to all items of the specified TargetType within that scope
For example, to make all TextBlock have FontWeight="Bold" and TextAlignment="Right" within a specific UserControl only, you can use something like this:
<UserControl.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="TextAlignment" Value="Right" />
</Style>
</UserControl.Resources>
If you put this in your resources, all your textblocks become the same.
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="TextAlignment" Value="Right"/>
</Style>
Alternatively, you can also subclass from TextBlock (say, BoldTextBlock) and use it as the target type. This is so you can use regular textblocks in the same control as special textblocks
<Style TargetType="{x:Type BoldTextBlock}">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="TextAlignment" Value="Right"/>
</Style>

Why does binding affect height?

Style definition in Resources/Shared.xaml (updated):
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:Double x:Key="fullHeight" >26</system:Double>
<system:Double x:Key="halfHeight" >16</system:Double>
<Thickness x:Key="m">10</Thickness>
<Style TargetType="Button">
<Setter Property="FontSize" Value="{StaticResource fullHeight}"/>
<Setter Property="Margin" Value="{StaticResource m}"/>
<Setter Property="Padding" Value="10"/>
</Style>
<Style TargetType="Label">
<Setter Property="FontSize" Value="{StaticResource fullHeight}"/>
<Setter Property="Margin" Value="{StaticResource m}"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource fullHeight}"/>
<Setter Property="Margin" Value="{StaticResource m}"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="FontSize" Value="{StaticResource fullHeight}"/>
<Setter Property="Margin" Value="{StaticResource m}"/>
<Setter Property="Padding" Value="10"/>
</Style>
<Style TargetType="PasswordBox">
<Setter Property="FontSize" Value="{StaticResource fullHeight}"/>
<Setter Property="Margin" Value="{StaticResource m}"/>
<Setter Property="Padding" Value="10"/>
</Style>
<Style TargetType="ListView">
<Setter Property="FontSize" Value="{StaticResource fullHeight}"/>
<Setter Property="Margin" Value="{StaticResource m}"/>
<Setter Property="Padding" Value="10"/>
</Style>
<Style TargetType="ComboBox">
<Setter Property="Margin" Value="{StaticResource m}"/>
</Style>
</ResourceDictionary>
Window:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/Shared.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
User control:
<StackPanel Orientation="Horizontal">
<Label Content="Text" Background="AliceBlue"/>
<Label Content="{Binding DecimalValue, FallbackValue=50}" Background="Aquamarine"/>
</StackPanel>
Model:
private decimal _DecimalValue;
public decimal DecimalValue
{
get { return _DecimalValue; }
set
{
if (_DecimalValue != value)
{
_DecimalValue = value;
NotifyOfPropertyChange();
}
}
}
I'm using Caliburn.Micro if it makes any difference.
Result:
Why?
Update: After some Snooping, it turns out that the inner TextBlock of the first Label has margin of 0 and Value Source is Default and for the second it's 10 and Style.
Update 2: After reading up this question it turns out that defined TextBlock style should not be applied to TextBlocks inside Labels. So it seems that existence of binding on a Label somehow changes that.
You must have some other style affecting it.
My best guess would be check your Padding properties, because when I copy and paste your styles to a new project, the heights and margins are the same as your image, however the Padding is different.
Your Labels are actually getting rendered like this:
<Label>
<Border>
<ContentPresenter>
<TextBlock />
</ContentPresenter>
</Border>
</Label>
By messing around with Snoop, I can duplicate your image by altering the Padding of the Border object, so check your XAML to see if you have any implicit styles that change the Padding of your Border tags
Update
After adding the extra styles you've added to your question, I am able to reproduce the results you are getting.
The problem appears to be that the implicit style for your TextBlock is being applied to the TextBlock inside the bound label, but not to the unbound one.
It should be noted this only happens when binding to a decimal value, not to a string.
I suspect this is related to the fact that implicit styles are not meant to cross template boundaries, unless the element inherits from Control. Label inherits from Control, however TextBlock does not.
Since this only happens when binding to a numeric value, my best guess is that the process that determines how to draw a Decimal for Label.Content identifies the parent control as a Label, while the process that writes a string to Label.Content automatically knows to use a TextBlock, and does not apply the implicit styles.

Resources