WPF ControlTemplate inherit style from parent resources - c#

I'm styling hyperlinks that appear within a border with the style "FooterPanel" as follows:
<Style x:Key="FooterPanel" TargetType="{x:Type Border}">
<Style.Resources>
<Style TargetType="{x:Type Hyperlink}">
<Setter Property="Foreground" Value="{StaticResource FooterPanelLinkBrush}"/>
</Style>
</Style.Resources>
</Style>
I also now have created a style to create a button as a hyperlink (so I can get properties such as IsDefault and IsCancel on a hyperlink):
<Style x:Key="LinkButton" TargetType="{x:Type Button}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Hyperlink Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}">
<Run Text="{TemplateBinding Content}"/>
</Hyperlink>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Normal hyperlinks within FooterPanel receive the FooterPanelLinkBrush foreground, but if I use LinkButton within a FooterPanel, the style is not applied. Is there a way to get the ControlTemplate to inherit the styles within the FooterPanel instead of any global hyperlink styles?
Edit:
According to this answer https://stackoverflow.com/a/9166963/2383681 there is special handling that means the Hyperlink won't receive the styles defined in the FooterPanel as it's not derived from Control.
I'm not sure what I'm trying to do is therefore possible without some code-behind, so I think I'm just going to workaround this and create a new style for FooterPanelLinkButton and explicitly reference this for the buttons that are in a footer panel. It would be interesting to know if this is possible however without doing that.

You can create a separate Style for the HyperLink:
<Style x:Key="FooterPanelLink" TargetType="{x:Type Hyperlink}">
<Setter Property="Foreground" Value="{StaticResource FooterPanelLinkBrush}"/>
</Style>
And then use this Style in the Resources of the FooterPanel and LinkButton styles in the following way:
<Style x:Key="FooterPanel" TargetType="{x:Type Border}">
<Style.Resources>
<Style TargetType="Hyperlink" BasedOn="{StaticResource FooterPanelLink}" />
</Style.Resources>
</Style>
<Style x:Key="LinkButton" TargetType="{x:Type Button}">
<Style.Resources>
<Style TargetType="Hyperlink" BasedOn="{StaticResource FooterPanelLink}" />
</Style.Resources>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Hyperlink Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}">
<Run Text="{TemplateBinding Content}"/>
</Hyperlink>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This way the HyperLink inside the LinkButton will use the color you assigned in the FooterPanelLink style.

Related

How to disable all custom styles in WPF

I override default styles of some controls in code. After this i want to disable all custom styles for all children(deep recursion) of some control. For example xaml:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Red"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Background" Value="Red"/>
</Style>
</StackPanel.Resources>
<Button>red style here is ok</Button>
<TextBlock> also ok</TextBlock>
<StackPanel>
<StackPanel.Resources>
<!-- magic command to disable ALL custom styles, for all controls like
<Style TargetType = "FrameworkElement"/> -->
</StackPanel.Resources>
<Button> no style plz </Button>
<TextBlock> bad style-_- </TextBlock>
</StackPanel>
</StackPanel>
I know that i can use style=null, but its bad solution for me, because i need to apply this trick for every type of controls. How can i solve my problem?
You could inject a blank Style that would take precedence over your other Style. Like:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Red"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Background" Value="Red"/>
</Style>
</StackPanel.Resources>
<Button>red style here is ok</Button>
<TextBlock> also ok</TextBlock>
<StackPanel>
<StackPanel.Resources>
<!-- magic command to disable ALL custom styles, for all controls -->
<Style TargetType="Button" />
<Style TargetType="TextBlock" />
</StackPanel.Resources>
<Button> no style plz </Button>
<TextBlock> bad style-_- </TextBlock>
</StackPanel>
</StackPanel>

How to modify WPF menu drop down visual?

I have a WPF menu:
XAML:
<Style x:Key="{x:Type ContextMenu}" TargetType="{x:Type ContextMenu}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContextMenu}">
<Border Background="#FF171616" CornerRadius="5" BorderBrush="DarkGray" BorderThickness="5" Opacity="0.0">
<StackPanel ClipToBounds="True" Orientation="Vertical" IsItemsHost="True" Margin="5,4,5,4"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Am I using the correct x:Type ContextMenu to alter the drop down visualization? The menu item visual is altered because I've manually changed the style. But it is the context drop down on which I want to apply visuals.
How can I modify the context drop down itself?
Here is a paint sample of what I'm after:
To modify style for menu, you need to override Menu style.
Like below:
<Style TargetType="{x:Type Menu}">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="#FF171616" />
</Style>
Edit: you can actually modify the whole template also, if you like. But I think these properties should get you the visualization you are looking for.

Abstract border and text block into another style/template in WPF

First of all, I would like to add customized text blocks to my GUI with the least possible overhead. For instance: <TextBlock style={StaticRessources myTextBlock}>Text</TextBlock>
For now I have the following border style:
<Style x:Key="greenBox" TargetType="Border">
<Setter Property="Background" Value="#00FF00"/>
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Height" Value="40"/>
<Setter Property="Width" Value="100"/>
</Style>
And I apply it in the following way:
<Border Style="{StaticResource greenBox}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Custom Text</TextBlock>
</Border>
My problem is, it needs 2 Tags and the properties set in the TextBlock will be redunant. I cannot figure out how to abstract both definitions into a single element.
that's where Label comes into play:
<Style TargetType="Label" x:Key="greenLabel">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Border Style="{StaticResource greenBox}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Label Style="{StaticResource greenLabel}">Custom Text</Label>
(in accordance with your other question: if this is the only place you use that borderstyle you can of course include these directly in that border not using an extra style)
You would need to create a custom control as described here. Or you could create a UserControl as well.

WPF StackPanel.Resources setter on more than one control type?

I want to use a setter to set a default margin of all elements in my stackpanel, not just buttons but also textboxes and labels.
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="0,10,0,0"/>
</Style>
</StackPanel.Resources>
...
When I try to change above Button to Control or FrameworkElement (a derived type of each element) it doesn't work.
How can I fix this without having to specify 2 different Style elements with the same content but different x:Types on the TargetType?
You can do this with inheritance via Style's BasedOn attribute:
<StackPanel.Resources>
<Style x:Key="BaseStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Margin" Value="0,10,0,0"/>
</Style>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseStyle}" />
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseStyle}" />
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseStyle}" />
</StackPanel.Resources>

Databound ContextMenu Separator not honoring global Separator Style

I have a context menu bound to a data source. For this context menu I have a DataTrigger to display a separator if the databound object has a value of "True" for the Separator property. This works well however it doesn't seem to pick up my global style for separators that I have in my application. The new separator appearance is different than the rest of my menu's. Is there a way to have it use the global style?
Below is the ContextMenu definition:
<ContextMenu
x:Key="ActionMenu"
ItemsSource="{Binding Source={StaticResource ActionMenuSource}}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Separator}" Value="true">
<Setter Property="MenuItem.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Separator Style="{DynamicResource {x:Static
MenuItem.SeparatorStyleKey}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
Here are my global values for defining the Separator.
<Style x:Key="{x:Static MenuItem.SeparatorStyleKey}" TargetType="{x:Type Separator}">
<Setter Property="Template" Value="{DynamicResource tmp_ManhMenuItemSeparator}"/>
</Style>
<ControlTemplate x:Key="tmp_ManhMenuItemSeparator" TargetType="{x:Type Separator}">
<Rectangle Name="SepRect" StrokeThickness="1" Stroke="White"/>
</ControlTemplate>
To make a style global the key needs to be the same as the TargetType which is clearly not the case in your sample. Change your key to "{x:Type Separator}" and see if that works for you. You can also merge your two snippets together unless you have a particular need to split them out, e.g.
<Style x:Key="{x:Type Separator}" TargetType="{x:Type Separator}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Separator}">
<Rectangle Name="SepRect" StrokeThickness="1" Stroke="White"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Once you have done that you can probably strip down the first block of code. It looks like you are trying to make the menu manually use the style. If you make it global you don't need to do that, e.g.
<ContextMenu x:Key="ActionMenu" ItemsSource="{Binding Source={StaticResource ActionMenuSource}}"/>

Categories