Styling an attached property with inheritance - wpf

My question is similar to this: WPF Style with no target type? but the problem is that mine is an attached property:
<Style TargetType="Shape" >
<Setter Property="z:Zommable.Unscale" Value="StrokeThickness" />
</Style>
My goal is: all object deriving from shape must have the attached property Zommable.Unscale with a value, but I can't find how to do it.
Thanks !

there is no difference to the other question. you will have to do exactly the same. So for each class deriving from Shape you will have to use a Style with that targettype that's BasedOn your style with your attached property.
So it's gonna be:
<Style x:Key="basicStyle">
<Setter Property="z:Zommable.Unscale" Value="StrokeThickness" />
</Style>
<Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource basicStyle}">
<!-- ... -->
</Style>
<Style TargetType="{x:Type Rectangle}" BasedOn="{StaticResource basicStyle}">
<!-- ... -->
</Style>
<!-- ... -->

Related

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}">

Cannot base style on another style

I have some locally defined styles within Window.Resources. I have some styles for a TextBlock, TextBox, CheckBox and RadioButton. These are supposed to be applied to all controls in the window, so I haven't provided a value for x:Key. I would like them to inherit from a style targeting FrameworkElement. So I have something like:
<Style TargetType="{x:Type RadioButton}">
...
</Style>
<Style TargetType="{x:Type TextBlock}">
...
</Style>
<Style TargetType="{x:Type TextBox}">
...
</Style>
<Style TargetType="{x:Type CheckBox}">
...
</Style>
<Style x:Key="TriggerBase" TargetType="{x:Type FrameworkElement}">
<Style.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="True">
...
</Trigger>
</Style.Triggers>
</Style>
My problem is that I am unable to set the BasedOn property to inherit from my TriggerBase style. After looking at similar questions, such as this and this, I still cannot get it working. These answers suggest you need to specify the TargetType on your base style, which I have done.
I thought maybe the Styles have to target the exact same type, but after digging around on MSDN I found that wasn't the problem:
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 type of the base style.
If I set BasedOn like BasedOn="{DynamicResource TriggerBase}", it can find my TriggerBase, but I get an error stating:
A 'DynamicResourceExtension' cannot be set on the 'BasedOn' property
of type 'Style'. A 'DynamicResourceExtension' can only be set on a
DependencyProperty of a DependencyObject.
If I try BasedOn="{StaticResource TriggerBase}", I get an error that it cannot find TriggerBase. One of the linked answers above showed using StaticResource like BasedOn="{StaticResource {x:Type FrameworkElement}, but it still cannot resolve the style.
How can I inherit from the TriggerBase style? I'm targeting .NET 4.5.
You are correct and you can base your styles on FrameworkElement style just need to move
<Style x:Key="TriggerBase" TargetType="{x:Type FrameworkElement}">
</Style>
to the top and then
<Style TargetType="{x:Type RadioButton}" BasedOn="{StaticResource TriggerBase}">
will work

How to extend instead of overriding WPF Styles

I want to use custom theme in my application and as far as I know I can accomplish this by using resource dictionary and referencing it in App.xaml. Styles would override the defaults like this:
<Style TargetType="{x:Type Label">
<Setter Property="Foreground" Value="Green" />
</Style>
Now as I guess the default Label style is overriden with same values but all my label fonts are green. The problem starts when I want to style one label somewhere again. When I want to change some other property in my Grid like this
<Grid.Resources>
<Style TargetType="{x:Type Label">
<Setter Property="FontSize" Value="28" />
</Style>
</Grid.Resources>
All labels inside my grid are losing their foreground color and have default one again (didn't I override defaults in previous step?). After some tries I found out that to do this properly i have to add another property to Style declaration BasedOn={StaticResource {x:Type Label}}" and it works. This is kind of weird for me because now I will have to repeat same BasedOn code in whole app and this is not how styling works - this should be done automatically! For example in HTML + CSS styles are inherited and merged and in WPF they are replaced...
Notice that when I don't use any styles controls still get their look from somehwere (System Themes?). How can I tell them to look for defaults somewhere else so without any additional code on styles they will think that they should be green by default?
Is there any way I can automate setting BasedOn property? Or maybe there is a better to do this overally?
I had the same problem. I used Zack's answer and improved it like following so if you don't specify a style the overridden default is still taken in account. It's basically what you would have done but just once in the ResourceDictionary.
<Window x:Class="TestWpf.RandomStuffWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Random Stuff Window">
<Window.Resources>
<ResourceDictionary>
<!-- Default Label style definition -->
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="Green" />
</Style>
<!-- Extending default style -->
<Style TargetType="{x:Type Label}"
x:Key="LargeGreenForegroundLabel"
BasedOn="{StaticResource {x:Type Label}}">
<Setter Property="FontSize" Value="28" />
</Style>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button Click="Button_Click">Click</Button>
<Label Content="GreenForegroundLabel" /> <!-- Uses default style -->
<Label Style="{StaticResource LargeGreenForegroundLabel}"
Content="LargeGreenForegroundLabel" />
</StackPanel>
</Window>
Wpf has different levels of styles, that are applied in order of global > local. A style set directly on a control will override a style set globally, like in your example. I was trying to find a list of all the different places that a control looks for its styles but I cannot find one at the moment. As far as I know, you will have to use the BasedOn property to inherit a style and not completely override the properties of that style with the style you set locally.
Here is an example of a resource dictionary that has styles based on another style, so that you don't have do repeat the BasedOn binding over and over, you can just set the style on the specific element you want to have that style.
<Window x:Class="TestWpf.RandomStuffWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Random Stuff Window">
<Window.Resources>
<ResourceDictionary>
<Style TargetType="{x:Type Label}"
x:Key="GreenForegroundLabel">
<Setter Property="Foreground" Value="Green" />
</Style>
<Style TargetType="{x:Type Label}"
x:Key="LargeGreenForegroundLabel"
BasedOn="{StaticResource GreenForegroundLabel}">
<Setter Property="FontSize" Value="28" />
</Style>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button Click="Button_Click">Click</Button>
<Label Style="{StaticResource GreenForegroundLabel}"
Content="GreenForegroundLabel" />
<Label Style="{StaticResource LargeGreenForegroundLabel}"
Content="LargeGreenForegroundLabel" />
</StackPanel>
</Window>

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>

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