Override item Style Template with a DataTemplateSelector - wpf

I've got a Style on ListViewItem that sets the Theme property
<Style x:Key="{x:Type ListViewItem}" TargetType="{x:Type ListViewItem}">
<Setter Property="Template" Value="{StaticResource ListViewItemTemplate}"/>
</Style>
However, in one of the cases where I'm using a ListView I want to use a DataTemplateSelector to determine which Template to use
<Style x:Key="MyListStyle" TargetType="{x:Type ListView}" BasedOn="{StaticResource {x:Type ListView}}">
<Setter Property="ItemTemplateSelector" Value="{StaticResource MyItemTemplateSelector}"/>
</Style>
It's applied like this
<ListView Style="{StaticResource MyListStyle}/>
However, it would appear that the Style on the item takes over and that style is applied to all the items in the ListView. I found this question which had a similar problem, however, the solution simply doesn't use the Template on the Item style at all. I need to keep that.
I've played around with the ContentTemplateSelector by restyling the ListViewItems in that ListView
<Style x:Key="MyItemStyle" BasedOn="{StaticResource {x:Type ListViewItem}}" TargetType="{x:Type ListViewItem}">
<Setter Property="ContentTemplateSelector" Value="{StaticResource MyItemTemplateSelector}"/>
</Style>
However, the Template on the other style is used instead. If I try nulling the Template then nothing shows up at all!
<Setter Property="Template" Value="{x:Null}"/
Is there a way that I can replace the Template on the ListViewItems for a given ListView while keeping the rest of my Style?

I was unable to override the Template set on the ListViewItem in the ListView Style.
To get around this I replaced the Template on the ListViewItem with another ItemTemplateSelector in my base ListView Style. This selector always returns my original Template. In my ListView child Style the new ItemTemplateSelector is used.

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

WPF Styles and Polymorphism

I know I'm a pervert, but I am very curious, is there a way to make custom controls to seek for it's base class style first, and then it's own.
Why I'm asking: I have some TreeView derived controls with custom item templates. I apply those templates, then I have a base style. Later I might apply some color palette. At the last step I have a problem. I need to apply 2 styles. PVStructuralTree is derived from TreeView it has some DependencyProperty DataTemplates that get inserted into resources in code.
PVStructuralTreeView
EmploeeTemplate
... more templates
Default style for PVStructuralTreeView:
<Style x:Key="DefaultPVStructuralTreeView" TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource DefaultTreeView}">
<Setter Property="EmploeeTemplate"><!-- This get inserted inro Resources in code -->
<Setter.Value>
<DataTemplate DataType="{x:Type s:Emploee}">
...
</DataTemplate>
</Setter.Value>
</Setter>
... Lots of them here
</Style>
<Style TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource DefaultPVStructuralTreeView}"/>
Default style for a TreeView (it's pretty big, so I won't post it here):
<Style TargetType="{x:Type TreeView}" BasedOn="{StaticResource DefaultTreeView}"/>
In color template.xaml file I'd like to have this + some magic to apply both styles at the same time (from Generic.xaml and themed one):
<Style x:Key="ThemedTreeView" TargetType="{x:Type TreeView}" BasedOn="{StaticResource DefaultTreeView}">
...
</Style>
<Style TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource ThemedTreeView}"/>
But it just overwrites generic.xaml styles. I want it to add to it.
Now I'm doing this way:
<Style x:Key="ThemedPVStructuralTreeView" TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource DefaultPVStructuralTreeView}">
... CopyPaste from ThemedTreeView ...
</Style>
<Style TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource ThemedPVStructuralTreeView}"/>
Does anyone knows the way how to reuse the ThemedTreeView style here?
You can base a Style on Another (one only!) Style using the BasedOn property and override specific properties, but you cannot base a DataTemplate or a ControlTemplate on another template. This is not supported. A template must be defined as a whole:
WPF: Is there a way to override part of a ControlTemplate without redefining the whole style?

How to use style from another resource in xaml

I need to change ScrollBar in my particular ListBox control. I have a ScrollBar style in another resource. But I don't know how to apply it. For example, I can apply a template from another resource, like this:
<ListBox
<ListBox.Resources>
<Style TargetType = "ScrollBar">
<Setter Property="Template" Value="{DynamicResource MyScbTemplate}"/>
</Style>
</ListBox.Resources>
</ListBox>
But I can't do the same with Style, like this:
<Style TargetType = "ScrollBar">
<Setter Property="Style" Value="{DynamicResource MyScbStyle}"/>
</Style>
You're on the right lines, you can't set the Style's Style inside the Style. (Yep.)
Instead, you need to inherit the parent style, like this:
<Style TargetType="ScrollBar" BasedOn="{DynamicResource MyScbStyle}">
For some more reading on BasedOn, see here.

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

WPF: Set style on immediate children only

In my application I have a tab control which has several tab items.
The problem is that I want to apply a style to these tab items, but to no other (nested) tab items.
I have tried setting the following style on the tab control, but this also effects all children:
<Style x:Key="tabControlStyle" TargetType="{x:Type TabControl}">
<Setter Property="TabItem.Template" Value="{StaticResource tabItemTemplate}" />
</Style>
By using the code above I get the following error: 'TabItem' ControlTemplate TargetType does not match templated type 'TabControl', as TabItem and TabControl have the same DependencyProperty "Template", and the code tries to set the TabItemTemplate as TabControl- Template.
Can anybody help me?
Use the ItemContainerStyle property to apply a style to the items of an items control:
<Style x:Key="tabControlStyle" TargetType="{x:Type TabControl}">
<Setter Property="ItemContainerStyle" Value="{x:StaticResource tabItemStyle}" />
</Style>

Resources