WPF MaterialDesign SolidColorBrush Value Conflict - c#

I am using Material Design to style my WPF app. I have used the following code to style a tab view:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Material Design -->
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Dark.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
<!-- Styles -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Dark.xaml" />-->
</ResourceDictionary.MergedDictionaries>
<!-- Tab Controller Primary Styles -->
<SolidColorBrush x:Key="PrimaryHueLightBrush" Color="#212121"/>
<SolidColorBrush x:Key="PrimaryHueLightForegroundBrush" Color="#212121"/>
<!-- This causes a clash between the tabview and the textbox colors -->
<SolidColorBrush x:Key="PrimaryHueMidBrush" Color="#212121"/>
<!--<SolidColorBrush x:Key="PrimaryHueMidBrush" Color="#BB86FC"/>-->
<SolidColorBrush x:Key="PrimaryHueMidForegroundBrush" Color="#FFFFFF"/>
<SolidColorBrush x:Key="PrimaryHueDarkBrush" Color="#212121"/>
<SolidColorBrush x:Key="PrimaryHueDarkForegroundBrush" Color="#212121"/>
</ResourceDictionary>
<!-- Tab Controller Secondary Styles -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="SecondaryAccentBrush" Color="#BB86FC"/>
<SolidColorBrush x:Key="SecondaryAccentForegroundBrush" Color="#BB86FC"/>
</ResourceDictionary>
<ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/materialdesign.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type dragablz:TabablzControl}" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}" />
</ResourceDictionary>
The issue I have is that to style the TabController primary style, it changes the color of the TextBox in my application.
When I apply a dark color to style the tab view, the TextBox loses its purple highlight.
But now in the second image, when I change the color back to purple for the TextBox, the TabView looks horrific.
They both depend on the same dictionary key for their styles. Is there a way I can change the x:Key value depending on what object type it is applied to? What is the best way to preserve the styles I need for both components.
This is for my university dissertation so I appreciate the help!
All the best.

The Material Design brushes are used in various styles of controls using DynamicResource. That means if you replace or register a brush with the same x:Key at runtime, all dynamic references will be adapted and the change will be applied to all controls in scope of the resource dictionary where you defined it.
In general, you would have to copy the default style and template for the control that you want to apply the changed color to and adapt it, e.g. by creating a separate brush and using it instead of the original, given the values are assigned in the control template directly instead of template bindings.
In case of the TabablzControl there might be an easier way. From its default style at GitHub, I can only see one usage of PrimaryHueMidBrush that is set as BorderBrush in a Setter. You can ovewrite this in your style.
<Style TargetType="{x:Type dragablz:TabablzControl}" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}">
<Setter Property="BorderBrush" Value="#212121"/>
</Style>
Of course, you could create a custom brush and reference it via DynamicResource instead of hardcoding it.
<Setter Property="BorderBrush" Value="{DynamicResource MyCustomPrimaryHueMidBrush}"/>

Related

Avalonia change part of FluentTheme

I use <FluentTheme Mode="Dark" /> for my application. I really like it but i want to change part of the design. For example swap the background to a bright pink.
I tried overriding the style like this:
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Avalonia.Test"
x:Class="Avalonia.Test.App">
<Application.DataTemplates>
<local:ViewLocator />
</Application.DataTemplates>
<Application.Styles>
<FluentTheme Mode="Dark" />
<Style>
<Style.Resources>
<Color x:Key="ThemeBackgroundColor">#CCFF0068</Color>
<SolidColorBrush x:Key="ThemeBackgroundBrush" Color="{DynamicResource ThemeBackgroundColor}" />
</Style.Resources>
</Style>
</Application.Styles>
But sadly it doesnt work. No errors are thrown but the change doesnt apply. Does anyone have a tip on how to only change part of the FluentTheme of avalonia?
For the Fluent theme the resource name is SystemControlBackgroundAltHighBrush.
I suggest overriding the resource instead of using style in your App.xaml -
<Application.Resources>
<SolidColorBrush x:Key="SystemControlBackgroundAltHighBrush" Color="#CCFF0068"/>
</Application.Resources>

How to change the font size in a mahapps project?

So I am trying to change the default font family and the font size in my project. I decided to start with buttons.
I do it like this (I am gonna create a separated file for my style, but now I just want to make it work somehow):
<Controls:MetroWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Templates/MyTemplateSelector.xaml"/>
<ResourceDictionary Source="/Templates/FullMenu.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style BasedOn="{StaticResource MetroButton}" TargetType="Button">
<Setter Property="FontFamily" Value="Calibri" />
</Style>
</ResourceDictionary>
</Controls:MetroWindow.Resources>
and nothing changes. What is wrong?
I guess it's because program can't find "{StaticResource MetroButton}".
App.xaml
<Application x:Class="WpfApp2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp2"
xmlns:dialogYesNo="clr-namespace:WpfApp2.DialogYesNo"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
<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" />
<!-- Accent and AppTheme setting -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
<ResourceDictionary Source="ViewModels.xaml" />
<ResourceDictionary Source="Dialogs.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
So, you just need to use it in App.xaml after declaring metro references:
<Style TargetType="Label">
<Setter Property="FontFamily" Value="Segoe UI Light"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI Light"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="FontFamily" Value="Segoe UI "/>
</Style>
Button uses TextBox, so button will be changed automatically.
Instead of define a style just to set fontfamily/weight you can just define in your resource directly the fontfamily and weight with a key(an example with a font that i use)
<Controls:MetroWindow.Resources>
<FontFamily x:Key="FontAwesome">/tuseradm;component/assets/fontawesome-webfont.ttf#FontAwesome</FontFamily>
</Controls:Flyout.Resources>
then in your button just set the font family
<Button FontFamily="{StaticResource FontAwesome}" Content="" />
EDIT adding another answer:
by default mahapps override the default wpf style. If you want to modify a style for let's say buttons in all your view you don't need to use based on
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="Button">
<Setter Property="FontFamily" Value="Calibri" />
<Setter Property="FontWeight" Value="ExtraLight"/>
</Style>
EDIT 2
At least for me, even if i see the change at design time using the approach exposed in the first edit, at run time the problem persist. So in my opinion, is much better to stick with my first answer. Maybe it could be annoying to set fontfamily and fontweight for each button, but it is the safest way to deal with mahapps styles. The only way to solve this 100% for sure is to find (no clue where) the template of mahapps buttons and modify it

Metro Styles in resource dictionary

I am trying to style my WPF application with Mahapps Metro. I have added the all the needed .xaml files in my MergedDictionary in the App.xaml. If I write the following in a view file,
<Button DockPanel.Dock="Left" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"/>
it works, i.e., the button is styled in the SquareButtonStyle style. But if I instead add the following in my own resource dictionary,
<Style TargetType="Button">
<Setter Property="Style" Value="{DynamicResource SquareButtonStyle}"/>
</Style>
I get an error message,
Setting of the property
"System.Windows.ResourceDictionary.DeferrableContent" has caused an
exception.
(my transation of the German error message). So how can I style all buttons, e.g., with SquareButtonStyle without having to do that on each button individually?
EDIT: Here is my app.xaml (the last dictionary, ResourceDic.xaml, is my own one where the above code is):
<Application xmlns:local="clr-namespace:MGM8" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:MGM8_BootStrapper p7:Key="bootstrapper" xmlns:p7="http://schemas.microsoft.com/winfx/2006/xaml" />
</ResourceDictionary>
<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 Source="ResourceDic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Style property can't be set inside Style of any element.
Just declare your style at root level(a root resource Dictionary or App.xmal resources). Just create the style with TargetType Button don't give any key to it. it will be applied to all the buttons in the app.
for ex:
<Style TargetType="Button" BasedOn="{StaticResource SquareButtonStyle}" >
<Setter Property="Height" Value="50"/>
<Setter Property="BorderThickness" Value="2,1" />
</Style>
So above is extending your SquareButtonStyle for your application for all buttons(only if defined at root level).
Update:
You have to use following in your own Resource Dictionary:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="SquareButtonStyle dictionary"/>
</ResourceDictionary.MergedDictionaries>
Then only you can create a button style based on SquareButtonStyle in your ResourceDictionary.

Windows Style from ResourceDictionary don't apply

As I have multiple Windows in my application, I am looking for a solution that does not require me to set a binding on each Window.
I created a ResourceDictionary which has a style for the Window Background:
<Style TargetType="{x:Type Window}">
<Setter Property="Background" Value="AliceBlue"/>
</Style>
In my XAML, I set the ResourceDictionary:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Templates.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
There is no error, but my Window color stays white.
This appears to be caused by a combination of the order in which WPF loads/processes styles from nested ResourceDictionary, and the specifics of the Window class.
Assume MainWindow is defined as per your post. Now put the following in Templates.xaml:
<Style TargetType="{x:Type Window}">
<Setter Property="Background" Value="Red"/>
</Style>
<Style TargetType="{x:Type Window}" x:Key="myStyle">
<Setter Property="Background" Value="Green"/>
</Style>
If MainWindow has no style defined, then you will see that in the designer it appears with a red background. The designer is parsing the whole Xaml and loading the resource dictionary, and then drawing the results. The style is read before the window is drawn, and so the red background is applied.
When you run the application, the window is created before the ResourceDictionary is applied. It looks for a default style (a style with x:Key="{x:Type Window}") before the nested ResourceDictionary is processed, and finds nothing. Therefore at runtime, the window appears with default colour. (This is the behaviour described in the comments above.) Remember that the style with x:Key="{x:Type Window}" has a default value that matches the Windows style.
This is borne out if you use myStyle explicitly. If you add to your Window definition the attribute Style="{StaticResource myStyle}" you'll find that the designer fails, but you also get a run-time error, because myStyle hasn't been created at the time that the Window needs it. If you switch to Style="{DynamicResource myStyle}" then you'll see that it works as you hope, because DynamicResource will update once the ResourceDictionary has been parsed and the style included.
So, applying this, you can fix the problem in one way by adding this to your Window element: Style="{DynamicResource {x:Type Window}}" - but this is cludgy. The better solution is to include your resource dictionary in the app.xaml file, where it will be parsed before any window is opened and thus available to all:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Templates.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
The real issue here is that your Window is not really a Window: it is a class that derives from Window and will in fact be MainWindow, Window2, etc... This means that the automatic style wireup for a Window will never work in this way, and some level of manual binding will unfortunately always be required.
This is the solution I used in my application. It lets me keep all my window styles together, and requires just a couple lines after the <Window.Resources> section.
Do your Style like so:
<Style x:Key="MyWindowStyle">
<Setter Property="Window.Background" Value="AliceBlue"/>
</Style>
Then, in your Window, after </Window.Resources> include the following:
<Window.Style>
<Style BasedOn="{StaticResource MyWindowStyle}"/>
</Window.Style>
Add a new brush in your resource dictionary
<SolidColorBrush x:Key="WindowBackground" Color="AliceBlue" />
and in your WPF window simply set the required resource to the window background property
<Window x:Class="GDD.Presentation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="300"
Background="{StaticResource WindowBackground}">

WPF - Mixing style defined in dictionary with style defined in parent control

I define a custom look for Button control in a resource dictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button" x:Key="BaseButtonStyle">
<Setter Property="Background" Value="Blue"/>
</Style>
</ResourceDictionary>
Then I try to change the style of the window where the buttons are located.
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary.xaml"/>
<ResourceDictionary>
<Style TargetType="Button" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
I have what I expected in WPF designer: a blue button with red text.
But in run-time, both styles are not applied and the button has default colors.
How can I fix this?
The one below works. I just moved the Style out of the MergedDictionaries and placed it on the outer ResourceDictionary.
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Button" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ResourceDictionary>
</Window.Resources>
In your original XAML, I'm not sure why the designer was able to render it correctly while the WPF runtime didn't. The MSDN documentation says though that:
A merged ResourceDictionary does not have resource elements defined within it in markup. Instead, the merged dictionary is a ResourceDictionary with no markup child elements defined (or with no elements added through code), but with a URI specified for Source.
It might have something to do with it.

Categories