I want to extend the number of colors in the System.Windows.Media.Brushes class, so I can do binding with the string name of the new Brush.
Like: value="myRed".
I use C#, .NET 4.5.2, VS2015, Windows 7.
This is not possible because the System.Drawing.Brushes class is sealed. This means it cannot be inherited from and therefore cannot be extended.
You are much better off creating a Resource Dictionary which contains your colours:
<ResourceDictionary ... >
<!-- Declare your colours here. -->
<SolidColorBrush x:Key="MyColour">#ffffff</SolidColorBrush>
</ResourceDictionary>
And then include that dictionary in your App.xaml:
<Application ... >
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- You may need to include more than one resource dictionary. -->
<ResourceDictionary Source="pack://application:,,,/Your.Project;component/Path/To/Dictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
You can get to those resources in the code-behind like this:
Brush myColour = (Brush)Application.Current.FindResource("MyColour");
In my opinion this is a much better way that extending the existing Brushes class because there's a clear divide between what is your code, and what is the .NET code. Not only that, having your colours in a resource dictionary promotes reuse across projects and the resources can be easily extended and become more adaptive to changing requirements.
You can find out more about resource dictionaries in the documentation.
Related
Before, in .NET Framework, when I created a WPF class library, I had my App.xaml (set as Application definition) referencing my resource dictionaries like that:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionary1.xaml" />
<ResourceDictionary Source="ResourceDictionary2.xaml" />
<ResourceDictionary Source="ResourceDictionary3.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
However, now, with .NET 5, I get this compilation error:
Library project file cannot specify ApplicationDefinition element.
So that message means I can't have an App.xaml file in a class library anymore. But now, I don't know how to define my resources globally in a class library. Isn't there any way to do this without referencing the dictionaries in each and every XAML file in the project?
Edit: It's not about the Source syntax. The path is correct and everything compiles perfectly if I set the project to Windows Application instead of Class Library.
refering to that github issue : https://github.com/dotnet/wpf/issues/2812#issuecomment-607537794
In an SDK style WindowsDesktop project,
*.xaml are all treated as Page items by default, unless they are named App.xaml (C#) or Application.xaml (VB).
App.xaml/Application.xaml is treated as ApplicationDefinition by default.
<!--
Disables automatic globbing of App.xaml/Application.xaml into
ApplicationDefinition item
App.xaml/Application.xaml would now get treated as any other *.xaml file
(typically, a Page)
-->
<PropertyGroup>
<EnableDefaultApplicationDefinition>false</EnableDefaultApplicationDefinition>
</PropertyGroup>
Worth a try.
For me works the following: If you have library-project with resources (i.e. namespace "Project.Resources") and have presentation-project (i.e. namespace "Project.Presentation"):
<Application x:Class="Project.Presentation.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Project.Resources;Dictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Don't forget to add reference to "Project.Resources" in "Project.Presentation".
I have a c# wpf-based class library with models, view models, and views, which I am using in multiple add-ins for dektop applications that have APIs which support hosted dockable WPF user controls. From here I can use different controls and launch dialogs to interact with various data structures in the 3rd-party application. My class library doesn't have an App.xaml file.
I have created a ResourceDictionary xaml file that I am using as a main style sheet throughout my views. In my user controls and windows, I reference it:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/styleMain.xaml"/>
</ResourceDictionary.MergedDictionaries
Inside of this style sheet, I manage my various controls to simplify and unify my views. At the lowest level, I have settings for things like font size, font family, and color. For example, I have several brushes that I use throughout my controls. One looks like this:
<Color x:Key="ColorBase_Primary" R="255" G="0" B="115" A="255"/>
<SolidColorBrush x:Key="Color_Primary" Color="{StaticResource ColorBase_Primary}"/>
This all works great for design and testing. However, I am referencing this class library in multiple other projects. In these other projects, I am hosting the main user control from my class library:
<UserControl x:Class="MyAppHost.ucDockingHost"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyAppHost"
xmlns:viewModels="clr-namespace:MyClassLibrary.ViewModels;assembly=MyClassLibrary"
xmlns:views="clr-namespace:MyClassLibrary.Views;assembly=MyClassLibrary"
mc:Ignorable="d">
<UserControl.DataContext>
<viewModels:vmMain/>
</UserControl.DataContext>
<Grid>
<views:ucMainGrid ViewModelMain="{Binding}" Property1="SomeValue" Property2="SomeOtherValue"/>
</Grid>
</UserControl>
Here I am setting DependencyProperties from the add-in application that references my class library without any problems, and all of my bindings and control behaviors are working great.
What I am now hoping to do is be able to specify from my add-in (and not the main class library) the basic resource values that are used throughout my style sheet, especially color (as in being able to change the value associated with x:Key="ColorBase_Primary"). This way, I can adapt different implementations to the branding of different clients, etc. I have been searching for a long time for any examples or insight and keep coming up short.
It would be easy enough to simply deploy the entire class library independently with each application and adjust the style sheet directly, but that doesn't seem right at all. Is there some way for me to create a ResourceDictionary in my add-in applications that could supply, modify or and/override the resource values specified in my class library? Or should I do it through a DependencyProperty in my view model? That doesn't seem right either.
Do not use the MergedDictionaries in your library, i.e. remove this:
In your application, you then merge all resource dictionaries from your library in the correct order:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/WpfControlLibrary1;component/Brushes.xaml"/>
<ResourceDictionary Source="pack://application:,,,/WpfControlLibrary1;component/Controls.xaml"/>
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="brush">Red</SolidColorBrush>
</ResourceDictionary>
</Application.Resources>
</Application>
You can then simply override any resource you want by defining another resource with the same x:Key like I have done with the SolidColorBrush above. This resource overrides any resource with an x:Key of "brush" defined in either Brushes.xaml or Controls.xaml.
I have a very simple requirement to use Light/Dark themed images. I expected that a qualifier like
SomeImage.Theme-Light.png
or putting the image under a folder named Theme-Light
Theme-Light/SomeImage.png
would work, and it did, but only in the designer mode. As soon as I run the app, even though the required theme is properly set (on both app and page level so all the other ThemeResources get loaded correctly), wrong image gets loaded.
I know about workarounds to load different images for different themes, so that's not what I'm looking for. I am curious to know why this approach with qualifiers doesn't work in runtime? Is there a different name qualifier that should be used?
I read this article: "How to name resources using qualifiers (XAML)" but it only shows how to name the assets with regards to high contrast support.
This aproach isn't as convenient as qualifiers, but it works.
Define in App.xaml
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<ImageSource x:Key="Logo">/Assets/Logo-White.png</ImageSource>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<ImageSource x:Key="Logo">/Assets/Logo-Blue.png</ImageSource>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<ImageSource x:Key="Logo">/Assets/Logo-White.png</ImageSource>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
Then use
<Image Source="{ThemeResource Logo}"/>
please forgive me in advance. First question.
I am working on a WPF project where I have defined a simple resource dictionary at the application level.
<Application x:Class="Game.UI.Modals.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary Source="GameResources.xaml"></ResourceDictionary>
</Application.Resources>
The reference to the ResourceDictionary is working fine; I am able to utilize it in XAML with no issues.
The problem I am having is in trying to add templates to the dictionary using the Create ControlTemplate Resource tool (right click => edit template => create empty). The Resource dictionary radio button in the define in panel is grayed out.
I have tried creating dictionaries in different namespaces, I made sure the dictionary is named and that the build action is set to resource.
Any idea how to get the Create ControlTemplate Resource dialog to recognize my application level ResourceDictionary?
Thanks!
Include your GameResources.xaml like this instead:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="GameResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
The create template dialog lists the merged dictionaries. When you include your resources as in my example, the radiobutton should become enabled and your merged dictionary should appear in the list.
In a WPF application I defined default control styles in separate resource dictionaries (e.g. "ButtonStyle.xaml"), and added them as merged dictionaries to a resource dictionary named "ResDictionary.xaml".
If I refer this "ResDictionary.xaml" as merged dictionary in my App.xaml, the default styles are not applied. However, if I refer the "ButtonStyle.xaml", it works correctly.
If I recompile the same code in .NET 3.5 or 3.0, it recognizes and applies the default styles referred in "App.xaml" through "ResDictionary.xaml", but not in .NET 4.0.
At runtime if I check the Application.Current.Resources dictionary, the default styles are there, but they are not applied, only if I specify the Style property explicitly in the Button control.
Are there any solutions to refer a resource dictionary (containig default styles) this way in .NET 4.0?
App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/ResDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
ResDictionary.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Default/ButtonStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
ButtonStyle.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button">
<Setter Property="Background" Value="Yellow"/>
</Style>
</ResourceDictionary>
The best solution is to add a dummy default style in the resource dictionary where you merge all resources together.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Style/Button.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Control" BasedOn="{StaticResource {x:Type Control}}" />
This could be caused by a known bug when there is a single style in application.resources within app.xaml when not using a startupuri.
The fix is to add an additional style like this...
...
<Style x:Key="unused" />
</Application.Resources>
for more details check out this link.... http://bengribaudo.com/blog/2010/08/19/106/bug-single-application-resources-entry-ignored
There is a sort-of fix for this, but I’ve only been able to make it work at the window level (not the application level).
In order to include a WPF 4.0 resource from a separate project, the resource must be added as a resource in the window’s code behind. The statement belongs in the window’s constructor, prior to the InitializeComponent method call:
public ControlsWindow()
{
this.Resources = Application.LoadComponent(new Uri("[WPF 4.0 ResourceProjectName];Component/[Directory and File Name within project]", UriKind.Relative)) as ResourceDictionary;
InitializeComponent();
}
Note: Replace the '[WPF 4.0 ResourceProjectName]' text with your resource's project name. Also, the '[Directory and File Name within project]' needs to be replaced with the relative location of the resource file (like 'Themes/StandardTheme.xaml')
I go into more details about this issue here.