Referencing external xaml resources dictionary file - c#

I have a project with several classes (It's a dll project). I added a xaml file (let's call it styles.xaml) in which I declared my most commonly in-use styles.
I have another project (let's call in prog), in a different solution, in which I would like to use the styles written in styles.xaml.
I tried right clicking prog --> add existing item, and I selected the styles.xaml, wrote all the relevant code, and it worked.
The problem is that it copied the styles.xaml file to my prog project's directory (hence I'm now holding two copies of the same resource file). Unlike regular dlls refrencing, it will always look for it in that directory, and not copy it again if it doesn't exist.
In terms of source control, I don't want to save many copies of the same resource file, one for each application, and in the current solution it appears like I must.
I also tried to add resource, and select that file - same issue.
Is there anyway of doing that?

for example you have in the styles.dll:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="BlueColor" Color="Blue"/>
<!-- Whatever Styles you need -->
</ResourceDictionary>
in a BlueTheme.xaml
then reference it with:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://siteoforigin:,,,/styles;component/BlueTheme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

Related

Window style not visible in designer

I created a Window style (WPF) and added it as a dll to my project
this style shows corretly when i run the program but doesn't show up in the designer.
I googled already but none of the solutions there are working
Test 1:
// Window //
Style="{DynamicResource HVE_Window}"
// Window.Resources //
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/GlobalHive.Styles;component/HiveWindow.xaml"/>
</ResourceDictionary.MergedDictionaries>
Result:
Error: 'Window' TargetType doesn not match type of element 'WindowInstance'
-> But it runs and display correctly there
Test 2:
// Window //
Style="{DynamicResource MyWindow}"
// Window.Resources //
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/GlobalHive.Styles;component/HiveWindow.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="MyWindow" TargetType="{x:Type Window}" BasedOn="{StaticResource HVE_Window}" />
Result:
No Error:
Still doesn't display in the designer, still shows up if i run the program
Test 3:
Both versions but added to application resources
How it should look:
How it looks inside the designer:
You can sometimes find that resources from a control library are not loaded at design time, despite whatever you put in app.xaml to try and load the things.
MS created a mechanism for Blend which you can use in visual studio since it's the blend designer.
This uses a "special" resource dictionary called DesignTimeResources.xaml
This will only be used at design time.
Add one to the Properties of your problem exe project.
With exactly that name.
Put all your merges into that.
eg this is one of mine from my MapEditor project that uses numerous resources from UILib. UILib is a control library with all sorts of UI stuff in it.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MapEditor">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/UILib;component/Resources/Geometries.xaml"/>
<ResourceDictionary Source="pack://application:,,,/UILib;component/Resources/ControlTemplates.xaml"/>
<ResourceDictionary Source="pack://application:,,,/UILib;component/Resources/FontResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/UILib;component/Resources/UILibResources.xaml"/>
<ResourceDictionary Source="/Views/Drawing/Terrain/Resources/CityResources.xaml"/>
<ResourceDictionary Source="/Resources/MapEditorResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Unload your csproj ( right click in solution explorer), edit it and find the node for that resource dictionary.
Change it to:
<Page Include="Properties\DesignTimeResources.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
<ContainsDesignTimeResources>true</ContainsDesignTimeResources>
</Page>
Reload the project, close and re-open visual studio.
Your styles should now apply.

Dark/Light theme assets qualifiers

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

Cannot find ResourceDictionary when editing copy of template

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.

WPF Designer Failing to Load Generic.xaml

I have written a WPF Class Library. It has a Generic.xaml file under a themes folder in the project and also a ThemeInfo attribute in the AssemblyInfo.cs file:
[assembly: ThemeInfo(
ResourceDictionaryLocation.None,
ResourceDictionaryLocation.SourceAssembly)]
All works well, except in the designer. I get blue squigly lines anywhere I am using StaticResource to reference my brushes, styles and other resources saying:
The resource '[Resource Name]' cannot be found.
I really want the designer to pick up my Generic.xaml file and show the controls as I have styled them. How can I achieve this?
UPDATE
I have marked Yogesh's answer as correct but here is some more information. I was adding the resource dictionary in the constructor of the App.xaml file, instead of in the xaml. The XAML designer does not seem to execute the code behind for the App.xaml file.
Just add a new page named App.xaml with Application as the root element in the class library with Build Action set to Page. Now add the generic.xaml file as a resource dictionary. Something like this...
<Application x:Class="[YourNamespace].App"
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="[AbsoluteOrRelativePath]/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
After you do this, rebuild your project, close all xaml views and reopen them again. This should fix your issue in VS2012/2013 and Blend 2012.

Have default string resource file and override it with custom ones

So the title is perhaps not completly clear.
I have a Strings.xaml file which contains several strings which are used in the application.
Strings.xaml
<!-- GENERAL FOR ALL TESTS -->
<my:String x:Key="AppTitle">AppName</my:String>
<my:String x:Key="TestName1">test_1</my:String>
<my:String x:Key="TestName2">test_2</my:String>
<!-- DEFAULT MESSAGES -->
<my:String x:Key="TestMessage">This is a default message</my:String>
<my:String x:Key="TestDescription">This is a default description</my:String>
<my:String x:Key="OnlyCustomInTest2">This string is used as a default message if not overridden by custom resource file</my:String>
</ResourceDictionary>
This resource file works great. What I'm wondering is if there is any built in way that I can use Strings.xaml as a default resource file and then override specific strings that are custom for different program modes? Like having Strings.xaml default and use Test_1_Strings.xaml and Test_2_Strings.xaml to override some strings for custom messages.
Test_1_Strings.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:System;assembly=mscorlib">
<!-- CUSTOM FOR TEST 1 -->
<my:String x:Key="TestMessage">This is a message for test 1</my:String>
<my:String x:Key="TestDescription">This is a description for test 2</my:String>
</ResourceDictionary>
Test_2_Strings.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:System;assembly=mscorlib">
<!-- CUSTOM FOR TEST 2 -->
<my:String x:Key="TestMessage">This is a message for test 2</my:String>
<my:String x:Key="TestDescription">This is a description for test 2</my:String>
<my:String x:Key="OnlyCustomInTest2">This is the overridden message for test 2</my:String>
</ResourceDictionary>
The reason I want to do this is because I have many different program modes where most of the resources are the same but some are custom. Instead of having to change a shared entry in 8 different resource files I could do it in only one place.
Resource lookup in WPF traverses from bottom to top i.e. any resource usage will first look for resource in its parent container which can be Grid, StackPanel etc. If not found in parent container will look for resource in parent's parent container and so on to UserControl, Window till it reach App resources.
Also, any resource later defined under resources section overrides the resource added previously with same key. This is true for resources defined under different resource dictionaries but not within the same XAML file. If you try to declare two items with same key, it will fail with key already exists exception.
You can take advantage of above stated features to your use.
Assuming you are merging the resources under App resources, what you can do is add Strings.xaml at top and then add other resource dictionaries Test_1_Strings.xaml and Test_2_Strings.xaml. This way resources with same name will be overridden and resource defined at last will always be resolved.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Strings.xaml"/>
<ResourceDictionary Source="Test_1_Strings.xaml"/>
<ResourceDictionary Source="Test_2_Strings.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
So when you declare TextBlock to refer to StaticResource TestMessage.
<TextBlock Text="{StaticResource TestMessage}"/>
it will print This is a message for test 2.
If you change the order and add Test_1 after Test_2, textBlock Text will be - This is a message for test 1.

Categories

Resources