2 Different ComboBox Styles with 2 Different ComboBoxItem Styles - c#

I have 2 ComboBox-Styles in my WPF-Application. They're look both like this:
<Style TargetType="{x:Type local:MyComboBox1}">
<Style.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Style.Resources>
<Setter Property="SnapsToDevicePixels" Value="true" />
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyComboBox1}">
...
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers />
</Style>
Now I want to style the ComboBoxItems for each ComboBox in a different way. How can i do this?

You can use the ItemContainerStyle property
<Style TargetType="Combobox" x:Key="myStyleOne">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ComboBoxItem">
<!-- put your style here -->
</Style>
</Setter.Value>
</Setter>
</Style>
And then you can use your style like the following.
<ComboBox Style="{StaticResource myStyleOne}" />

Related

How can I style only those Buttons which are in a DataGrid?

In App.xaml I have styled all my Buttons.
<Style TargetType="Button">
<Setter Property="Margin" Value="3"/>
</Style>
I realized if the Button is in a DataGrid then I not need a margin. I have a lot of DataGrid and I put this code into all of them one by one.
<DataGrid.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="0"/>
</Style>
</DataGrid.Resources>
Is there a more clever way to do this?
You can define Style for DataGrid and within that, add child control style to particular modification.
If you want to add this Style to all the DataGrids, no need to defineKey.
<Style x:Key="dataGrid" TargetType="DataGrid">
<Style.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="0" />
</Style>
</Style.Resources>
</Style>
Declare a style with the key in the Window.Resources or App.Resources as shown below.
<Window.Resources>
<Style TargetType="Button" x:Key="dataGridButtonStyle">
<Setter Property="Margin" Value="3"/>
<Setter Property="Background" Value="Wheat"/>
</Style>
</Window.Resources>
Then apply the style to the control using the StaticResource with the key(in this example key name is dataGridButtonStyle)
<Button Style="{StaticResource ResourceKey= dataGridButtonStyle}" Content="Hello"/>
Please add resource file at Windows or User control level so that it will apply all child controls as below,
<Window.Resources>
<Style TargetType="DataGrid">
<Style.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Red" />
<Setter Property="Margin" Value="0" />
</Style>
</Style.Resources>
</Style>
<Window.Resources>
or
<UserControl.Resources>
<Style TargetType="DataGrid">
<Style.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Red" />
<Setter Property="Margin" Value="0" />
</Style>
</Style.Resources>
</Style>
</UserControl.Resources>

How do I access an element of a parent template style in XAML?

I am having trouble accessing a named element of a parent template style in WPF.
I have a custom control for a Button (written per this StackOverflow question):
CustomButton.xaml:
<ResourceDictionary ...>
<Style x:Key="ButtonCustomStyle" TargetType="{x:Type local:ImageButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ImageButton}">
<Grid>
<Image Source="{TemplateBinding Image}" Stretch="Fill" x:Name="CurrentImage"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="CurrentImage" Property="Source" Value="{Binding ImageHover, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
MainWindow.xaml:
<Window ...>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CustomButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type local:ImageButton}" BasedOn="{StaticResource ButtonCustomStyle}"/>
</ResourceDictionary>
</Window.Resources>
<Grid>
<local:ImageButton Image="\Images\image.png" ImageHover="\Images\image_hover.png" Width="20" Height="20"/>
</Grid>
ImageButton inherits Button, and Image and ImageHover are defined as dependency properties. This code works great and does what expected.
Now, I want to extend this template style for a single particular button, adding an additional Trigger for changing the image of the button. I am trying to do the following:
<Window...>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CustomButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type local:ImageButton}" BasedOn="{StaticResource ButtonCustomStyle}"/>
<Style TargetType="{x:Type local:ImageButton}"
BasedOn="{StaticResource ButtonCustomStyle}"
x:Key="Disableable">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="CurrentImage" Property="Source" Value="\Images\disabled.png"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<local:ImageButton Image="\Images\image.png" ImageHover="\Images\image_hover.png" Width="20" Height="20"/>
<local:ImageButton Style="{StaticResource Disableable}" Image="\Images\image.png" ImageHover="\Images\image_hover.png" Width="20" Height="20"/>
</Grid>
But Visual Studio underscores the new setter line and says 'The name "CurrentImage" is not recognized'.
Is there a way to alter the CurrentImage element?
I am having trouble accessing a named element of a parent template style in WPF.
This is not possible. You can't base a ControlTemplate on another ControlTemplate.
I am afraid you will have to re-define the entire ControlTemplate from scratch in the derived Style if you want the setter to be able find the CurrentImage element that is defined in the template of the base Style.
WPF: Is there a way to override part of a ControlTemplate without redefining the whole style?
But instead of using a ControlTemplate trigger, you should be able to use a Style trigger that sets the Image property of the control itself rather than setting the Source property of the Image element in the template:
<Style x:Key="ButtonCustomStyle" TargetType="{x:Type local:ImageButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ImageButton}">
<Grid>
<Image Source="{TemplateBinding Image}" Stretch="Fill" x:Name="CurrentImage"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Image" Value="{Binding ImageHover, RelativeSource={RelativeSource Self}}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type local:ImageButton}"
BasedOn="{StaticResource ButtonCustomStyle}"
x:Key="Disableable">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Image" Value="\Images\disabled.png"/>
</Trigger>
</Style.Triggers>
</Style>
Unlike ControlTemplete trigger, Style trigger doesn't have access to template elements. since you exposed Image property, use it in Style trigger setter:
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Image" Value="\Images\disabled.png"/>
</Trigger>

WPF Auto-assign styles to children through parent style

I got several StackPanels in my application which want their children to apply certain styles:
<StackPanel.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource SettingLabel}" />
<Style TargetType="DockPanel" BasedOn="{StaticResource SettingRow}" />
<Style TargetType="CheckBox" BasedOn="{StaticResource SettingCheckBox}" />
<Style TargetType="PasswordBox" BasedOn="{StaticResource DialogPasswordBox}" />
<Style TargetType="TextBox" BasedOn="{StaticResource DialogTextBox}" />
</StackPanel.Resources>
Instead of writing these 5 lines over and over again I though of giving the StackPanel itself a style which will apply those and therefore reduce redundancy.
It is not possible to set Resources in a style setter because it's no dependency property:
<Style x:Key="SettingPanel" TargetType="StackPanel">
<Setter Property="Resources">
<Setter.Value>
<Style TargetType="TextBlock" BasedOn="{StaticResource SettingLabel}" />
<Style TargetType="DockPanel" BasedOn="{StaticResource SettingRow}" />
<Style TargetType="CheckBox" BasedOn="{StaticResource SettingCheckBox}" />
<Style TargetType="PasswordBox" BasedOn="{StaticResource DialogPasswordBox}" />
<Style TargetType="TextBox" BasedOn="{StaticResource DialogTextBox}" />
</Setter.Value>
</Setter>
</Style>
So is there any other way to do this without having to set the styles on every child and repeat the assignment styles?
You can define styles in Style.Resources of StackPanel. These will be applied to all the children of StackPanel using SettingPanel as style.
<Style x:Key="SettingPanel" TargetType="StackPanel">
<Style.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource SettingLabel}" />
<Style TargetType="DockPanel" BasedOn="{StaticResource SettingRow}" />
<Style TargetType="CheckBox" BasedOn="{StaticResource SettingCheckBox}" />
<Style TargetType="PasswordBox" BasedOn="{StaticResource DialogPasswordBox}" />
<Style TargetType="TextBox" BasedOn="{StaticResource DialogTextBox}" />
</Style.Resources>
</Style>

WPF ControlTemplate inherit style from parent resources

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.

Style "Cannot find resource 'MetroCheckBox'" in MahApps

I'm starting to use styles in WPF. I'm using MahApps styles as a base, which so far has been really good. I've been able to make specific modifications using the BasedOn property.
One of the simpler changes is to add a default margin so when adding controls they don't touch. It's worked really well so far until I tried to use the MetroCheckBox. With this specific control it throws an xaml parse exception: "Cannot find resource named 'MetroCheckBox'. Resource names are case sensitive."
I had a look in the source code, trying to track down this issue and coppied the name directly from the GitHub:
https://github.com/MahApps/MahApps.Metro/blob/master/MahApps.Metro/Styles/Controls.CheckBox.xaml
It's definately and all my other controls work fine:
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MetroButton}">
<Setter Property="Margin" Value="2"/>
</Style>
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource MetroComboBox}">
<Setter Property="Margin" Value="2"/>
</Style>
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource MetroCheckBox}">
<Setter Property="Margin" Value="2"/>
</Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource MetroTextBox}">
<Setter Property="Margin" Value="2"/>
</Style>
Any ideas on how to fix this?
Note, I'm including the reference to the styles like so:
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:extra="http://schemas.extra.com/ui"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:visualizationToolkit="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:Primitives="clr-namespace:System.Windows.Controls.DataVisualization.Charting.Primitives;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
xmlns:Custom="http://metro.mahapps.com/winfx/xaml/controls"
x:Class="MyApp.App"
StartupUri="/MyApp;component/GUI/Window/Window3.xaml"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MetroButton}">
<Setter Property="Margin" Value="2"/>
</Style>
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource MetroComboBox}">
<Setter Property="Margin" Value="2"/>
</Style>
<!--<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource MetroCheckBox}">
<Setter Property="Margin" Value="2"/>
</Style>-->
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource MetroTextBox}">
<Setter Property="Margin" Value="2"/>
</Style>
<!--Chart Style-->
<Style TargetType="{x:Type chartingToolkit:Chart}
...
</Style>
<!--Top Tab Item-->
<Style x:Key="TopTabItemStyle" TargetType="{x:Type TabItem}" BasedOn="{StaticResource {x:Type TabItem}}">
...
</Style>
<!--Tab Item-->
<Style TargetType="{x:Type TabItem}" BasedOn="{StaticResource MetroTabItem}">
...
</Style>
<!-- Group Box-->
<Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource MetroGroupBox}">
<!--<Setter Property="Margin" Value="5"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Foreground" Value="{DynamicResource BlackBrush}"/>
<Setter Property="Background" Value="{DynamicResource AccentColorBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource AccentColorBrush}"/>
<Setter Property="Custom:ControlsHelper.HeaderFontSize" Value="{DynamicResource ContentFontSize}"/>
<Setter Property="Custom:GroupBoxHelper.HeaderForeground" Value="{x:Null}"/>-->
<Setter Property="Custom:ControlsHelper.HeaderFontWeight" Value="SemiBold"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupBox}">
<Grid x:Name="GroupBoxRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0,0,2" Background="Transparent" Grid.Row="0">
<ContentPresenter ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" TextElement.FontWeight="{TemplateBinding Custom:ControlsHelper.HeaderFontWeight}" TextElement.FontStretch="{TemplateBinding Custom:ControlsHelper.HeaderFontStretch}" TextElement.FontSize="{TemplateBinding Custom:ControlsHelper.HeaderFontSize}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True"/>
</Border>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" Background="Transparent" Grid.Row="1">
<ContentPresenter Cursor="{TemplateBinding Cursor}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
You are missing the required ResourceDictionary to bring in the styles for the MahApps. You can do by including the ResourceDictionary definition in the XAML of either the XAML file where you are composing your view or you can add it to the APP.XAML file - the later will give you better performance in the short term.
For example: here is the MahApps controls xaml included with other MahApps resource dictionaries, the controls xaml is the one you need in this case:
<Application x:Class="MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
I ran it today and it works fine:
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource MetroComboBox}">
<Setter Property="Margin" Value="2"/>
</Style>
As far as I can tell I've changed nothing to do with the project or references.
However, in the last few days Visual Studio had corrupted somehow with the designer throwing exceptions left right and center, solution explorer failing to display anything (was fixed after clearing Component Model Cache) and NuGet failing to work for me to check the MahApps version.
So I set off the installer on a repair install, and now the style works fine.
I have no idea if these are connected... but they may be, so I'll leave this up as an answer in case anyone else comes across this same issue.
This can be caused if you upgrade from a version of MahApps prior to 2.0 to a more recent version.
For more details, see:
mahapps.com: Migration to v2.0 - MahApps.Metro
https://mahapps.com/docs/guides/migration-to-v2.0

Categories