WPF Style BasedOn not working as expected - wpf

Why do my Radiobutton not look like a togglebutton?
Take a look at the code
<Style x:Key="ButtonBaseStyle" TargetType="{x:Type ButtonBase}">
<Setter Property="Height" Value="100" />
</Style>
<Style BasedOn="{StaticResource ButtonBaseStyle}" TargetType="{x:Type Button}" />
<Style BasedOn="{StaticResource ButtonBaseStyle}" TargetType="{x:Type ToggleButton}" />
<Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="{x:Type RadioButton}" />
<StackPanel>
<Button>Button</Button>
<ToggleButton>Toggle</ToggleButton>
<RadioButton>Radio</RadioButton>
</StackPanel>
If I remove the buttonbase style it works

The looks of your RadioButton is not as ToggleButton cause of you have now changed the style hierarchy of ButtonBase->ToggleButton->RadioButton (the order in which styles and templates are overwritten in derived classes of WPF).
Your new hierarchy of style gives the most priority to the style of ButtonBase. So you have a new ToggleButton style that is derived from a ButtonBase and then you overwrite the RadioButton style with that. So noone can tell you for sure which properties have you overwritten and which will be the final set of properties.
To understand this change the XAML as following:
<Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="{x:Type ToggleButton}" />
<Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="{x:Type RadioButton}" />
and now see the look & feel of your RadioButton.
I'm not clarifying what is exactly happened and why your ToggleButton is not affected so much.
But as I said it's all about the style hierarchy which is build for a control at last just before rendering on the UI.

Related

Deriving style from base style fails WPF

I just realized that deriving from default style fails in my WPF app and I have no idea, why. Actually it works, but only due to "Hot reload". So I have:
<Style TargetType="ComboBox" x:Key="TestStyle" BasedOn="{StaticResource {x:Type ComboBox}}"/>
<Style TargetType="ComboBox">
<Setter Property="Width" Value="100"/>
</Style>
in resource dictionary, and:
<ComboBox Style="{StaticResource TestStyle}">
<ComboBoxItem>test</ComboBoxItem>
<ComboBoxItem>I want to cry with blood</ComboBoxItem>
</ComboBox>
in my control. When I start app I see following:
And when I remove BasedOn="{StaticResource {x:Type ComboBox}}" and add it again, I have correct view:
What can be a reason of such behavior? Seems like WPF bug, but I don't think this is possible
To find correct style you need to define it before "TestStyle"
<Style TargetType="ComboBox">
<Setter Property="Width" Value="100"/>
</Style>
<Style TargetType="ComboBox" x:Key="TestStyle" BasedOn="{StaticResource {x:Type ComboBox}}"/>

WPF overriding ListViewItem style when use Material Design In XAML Toolkit

I installed Material Design In XAML Toolkit to my project. I have ListView which contains within itself GridView (with GridViewColumns) and i want to override styles for each row in this table. But in each case i lose styles from Material Design In XAML Toolkit.
I tried do several things:
1) Override existing styles based on target type:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem" BasedOn="{StaticResource {x:Type ListViewItem}}">
<Setter Property="Background" Value="Green" />
</Style>
</ListView.ItemContainerStyle>
I got overriding styles, but in this case i lose type recognition in GridView (Columns contains correct headers, but values contains call result ToString() method my model)
2) I used concrete style from Material Design In XAML Toolkit - MaterialDesignGridViewItem:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem" BasedOn="{StaticResource MaterialDesignGridViewItem">
<Setter Property="Background" Value="Green" />
</Style>
</ListView.ItemContainerStyle>
In this case i got work solution (it would seem), but when i do adding triggers instead , i lose material styles (got only color, without animations).
3) In other cases i lose all material styles and go back to wpf default styles.
Hope on our help.
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem" BasedOn="{StaticResource MaterialDesignListBoxItem">
<Setter Property="Background" Value="Green" />
</Style>
</ListView.ItemContainerStyle>
Instead of using MaterialDesignGridViewItem, your extended style should be based on MaterialDesignListBoxItem.
The same works for other items. This helped me with TreeViewItem's that used to be in the style of MaterialDesign, but were also overwritten until I added the BasedOn property.
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource MaterialDesignTreeViewItem}">
<EventSetter Event="TreeViewItem.DragOver" Handler="treeView_DragOver"/>
<EventSetter Event="TreeViewItem.Drop" Handler="treeView_Drop"/>
<EventSetter Event="TreeViewItem.MouseMove" Handler="treeView_MouseMove"/>
<EventSetter Event="TreeViewItem.MouseLeftButtonDown" Handler="treeView_MouseDown"/>
<EventSetter Event="TreeViewItem.MouseRightButtonDown" Handler="treeView_MouseRightDown"/>
</Style>
</TreeView.ItemContainerStyle>
Please note a "}" is missing after "MaterialDesignListBoxItem", so that:
<Style TargetType="ListViewItem" BasedOn="{StaticResource MaterialDesignListBoxItem}">

Defining default layout properties

I want to set consistent margins throughout all controls within an entire view. I currently use XAML:
<Window.Resources>
<Thickness x:Key="ConsistentMargins">0,10,0,0</Thickness>
</Window.Resources>
<!-- ... -->
<!-- ... -->
<!-- ... -->
<MyControl1 Margin="{StaticResource ConsistentMargins}">
<MyControl2 Margin="{StaticResource ConsistentMargins}">
<MyControl3 Margin="{StaticResource ConsistentMargins}">
Is there a way to set a default layout style for controls to avoid the above repeated code shown above?
You can create your own style with TargetType and this style will be assigned to all object of type which you specified in TargetType. But in this case your created style will be applied only for speciefied type of object, but not for derived type.
E.g. you can create style for all buttons like this:
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="0,10,0,0" />
</Style>
I think that this makes sense that style is not applied from base class, because I want say "My all buttons looks like...", but I want not say "Everything looks like...".
You may create a base default style, perhaps for FrameworkElement, and let the default styles for other element types extend the base style:
<Window.Resources>
<Style TargetType="FrameworkElement">
<Setter Property="Margin" Value="0,10,0,0"/>
</Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type FrameworkElement}}"/>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type FrameworkElement}}"/>
<Style TargetType="Label" BasedOn="{StaticResource {x:Type FrameworkElement}}"/>
...
</Window.Resources>

WPF - Use control inheritance for standard-styled controls?

I have a WPF application with many windows and user controls, and I'd like to implement standard styles for certain controls that appear throughout the application. As an example, say I need two standard TextBlocks throughout the application: one for large headings, one for small headings. And the only difference between them is the font size, say 36 and 24 respectively. All other properties (color, fontfamily, etc.) could be set by a TextBlock template or global TargetType="{x:Type TextBlock}" styles.
Of course I could create two global named styles that just set the font size and apply those staticresource styles liberally throughout the XAML to my TextBlocks, or at the highest possible level above the TextBlocks that would not interfere with other TextBlocks. But as an alternative, which would remove the requirement for setting the Style tag in many places, is inheriting from TextBlock is a good way to go?
TextBlock controls:
class TextBlockLargeHeading : TextBlock
{
public TextBlockLargeHeading()
{ }
}
class TextBlockSmallHeading : TextBlock
{
public TextBlockSmallHeading()
{ }
}
Global resource:
<Application.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
</Style>
<Style TargetType="MyApp:TextBlockLargeHeading" BasedOn="{StaticResource {x:Type TextBlock}}" >
<Setter Property="FontSize" Value="36" />
</Style>
<Style TargetType="MyApp:TextBlockSmallHeading" BasedOn="{StaticResource {x:Type TextBlock}}" >
<Setter Property="FontSize" Value="24" />
</Style>
</Application.Resources>
Then, to use them anywhere, simply reference the custom textblocks:
<StackPanel>
<MyApp:TextBlockLargeHeading Text="Large" />
<MyApp:TextBlockSmallHeading Text="Small" />
</StackPanel>
Which would create two Red TextBlocks with the appropriate font sizes.
Is this a reasonable approach? Are there any gotcha's if I've got 100's of instances of these, maintainability-wise or otherwise? Is there a better (safer or less code/XAML) approach? Perhaps using User Controls instead?
Thanks!
There's no reason to do all that. Create your styles and use them directly.
....
<Style x:Key="DefaultTextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontSize" Value="24" />
</Style>
<Style x:Key="LargeTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource DefaultTextBlockStyle}">
<Setter Property="FontSize" Value="36" />
</Style>
<!-- Style applies to all TextBoxes -->
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource DefaultTextBlockStyle}" />
...
<StackPanel>
<TextBlock Text="Large" Style="{StaticResource LargeTextBlockStyle}"/>
<TextBlock Text="Small"/>
</StackPanel>

In WPF, Is there any way to combine two Style for one control?

My situation is like following.
I have a App.xaml which includes Style for ListView like this:
<Style x:Key="{x:Type ListViewItem}" TargetType="ListViewItem">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
...
However, I wanna add some styles into another xaml, let's say in Window.xaml like this:
<ListView AlternationCount="2" Background="#FFECECEC">
<ListView.Resources>
<Style x:Key="{x:Type ListViewItem}" TargetType="{x:Type ListViewItem}">
<EventSetter Event="PreviewMouseDoubleClick" Handler="OnPreviewMouseDoubleClick" />
</Style>
</ListView.Resources>
</ListView>
So, what I want to do is define style for base design in App.xaml as Default style.
Then, add some modify such as adding a context menu, adding events from each xaml.
But, with above implementation, Style defined in App.xaml will be overwrote by Style defined in Window.xaml.
Is there any way to solve the issue and achieve it?
Styles have a BasedOn property:
<Style x:Key="Style1">
...
</Style>
<Style x:Key="Style2" BasedOn="{StaticResource Style1}">
...
</Style>
Btw: <Style x:Key="{x:Type ListViewItem}" seems a bit weird. The x:Key should be a unique key in a xaml dictionary - usually a string.
If the BasedOn attribute fits your needs, it's the best choice. For more complicated scenarios though, something like the solution referred to in this question is more flexible.

Resources