XAML - Using fonts from resource dictionary from another assembly - wpf

I am building an application that uses ResourceDictionaries from another assembilies and I'm having problems with using fonts.
There is an assembly named MyFontAssembly that stores fonts along with references to them as an ResourceDictionary. The structure of it looks as follows:
MyFontAssembly
- FontDictionary.xaml - (stores references to fonts)
- Fonts
- FontA.ttf
- FontB.ttf
...
There is also another assembly that stores ResourceDictionaries for styling controls and it's called MyStylesAssembly. ResourceDictionaries from MyStylesAssembly are then merged in an App.xaml of an application in order to provide reusable styles.
The problem is that my styles does recognise font resources (the code is not crashing because it couldn't find resource by its key), but it looks like fonts stored as ttf files were not applied.
I have tried the following in my FontDictionary.xaml, but none of it works:
<FontFamily x:Key="MyFontKey">Fonts/#MyFontName</FontFamily>
<FontFamily x:Key="MyFontKey">pack://application:,,,/MyFontAssemblyName;Component/Fonts/#MyFontName</FontFamily>
<FontFamily x:Key="MyFontKey">/MyFontAssemblyName;Component/Fonts/#MyFontName</FontFamily>
<FontFamily x:Key="MyFontKey">pack://application:,,,/Fonts/#MyFontName</FontFamily>
NOTE:
I am sure that my fonts form ttf work and are named correctly. I was using <FontFamily x:Key="MyFontKey">Fonts/#MyFontName</FontFamily> implementation in the single exe project with the same structure and everything was just fine, the problem appeared when I have split the implementation into few assemblies, just like I described, during refactoring.
MyFontAssembly is merged in MyStylesAssembly correctly. I just call it by that name here, in real code it has also a few more ResourceDictionaries that are used correctly by MyStylesAssembly. The problem appears to be with just <FontFamily> tags not recognising ttf files.
MyFontAssembly and MyStylesAssembly are projects of tyle ClassLibrary and does not contain any code other than in ResourceDictionaries (no classes or code behind)

Found an answer here. I had to set build action to resource, then reference them by using:
<FontFamily x:Key="MyFontKey">pack://application:,,,/MyFontAssemblyName;Component/Fonts/#MyFontName</FontFamily>
or the shorter version:
<FontFamily x:Key="MyFontKey">/MyFontAssemblyName;Component/Fonts/#MyFontName</FontFamily>

Create A WPF Class Library.Lets Say FontLibraryCommon
Now Delete App.Xaml and MainWIndow.Xaml as shown below
Now change the project properties to class library and compile
Now Add Font Folder and existing TTF files under it as shown. I use Pacifico font for example
Now add ResourceDictioanry let say FontDictioanry.xaml in your library
and your xaml should look like this
Here is the code
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:FontLibraryCommon">
<FontFamily x:Key="Pacifico">Fonts/#Pacifico</FontFamily>
</ResourceDictionary>
Now in your other project add Font Library as reference
And in your MainWindow.Xaml `
<Window.Resources>
<ResourceDictionary Source="pack://application:,,,/FontLibraryCommon;component/FontDictioanry.xaml"></ResourceDictionary>
</Window.Resources>`
And last Lets Say label you can set like this
<Label FontFamily="{StaticResource Pacifico}"> Raman</Label>

Here is one way to reference a font from deferent library.
Say we have library called MyAwesomeFonts and here is its project structure:
MyAwesomeFontsLibrary
|
|__ Fonts\
| |
| |__ Fonts.cs
| |__ MyAwesomeFont.ttf
|
|__ Themes\
|
|__ generic.xaml
In the Fonts\ folder you put your fonts, and in the generic.xaml file you declare your font normally like this:
xmlns:fonts="clr-namespace:MyAwesomeFontsLibrary.Fonts"...
<FontFamily
x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type fonts:Fonts}, ResourceId=MyAwesomeFont}">Fonts/#My Awesome Font Name</FontFamily>
and in the Fonts.cs file contains:
// say this class declared in namespace: MyAwesomeLibrary.Fonts
public class Fonts
{
public static ComponentResourceKey MyAwesomeFontKey => new ComponentResourceKey(typeof(Fonts), "MyAwesomeFont");
}
For every font you have you do the same things done above, you add them to Fonts folder, declare them as resource in generic.xaml file and finally create a static property in Fonts.cs
Now build your library, add reference to it in project where you want to use it and add a namespace of your AwesomeFontsLibrary to your XAML something like that:
<... xmlns:fonts="clr-namespace:MyAwesomeFontsLibrary.Fonts;assembly=MyAwesomeFontsLibrary" >
Now here is two snippets of reusing your AwesomeFontsLibrary Fonts in TextBlock and style:
In Style:
<Style x:Key="MyTextBlockStyle"
TargetType="TextBlock">
<Setter Property="FontFamily" Value="{DynamicResource {x:Static fonts:Fonts.MyAwesomeFontKey}}"></Setter>
</Style>
Or directly in Textblock:
<TextBlock FontFamily="{DynamicResource {x:Static fonts:Fonts.MyAwesomeFontKey}}" FontSize="50">Welcome!</TextBlock>
You must use Dynamic Resource, not static resource, when using a ComponentResourceKey
Your new font my not appear in designer window but in runtime it will work.
Steps above are tested on my machine and they work. Hopefully this will help.

Related

Override Control Style

I have created a CustomControlLibrary.dll, that contains a Control (MyControl), with its style in the Generic.xaml of the Themes folder, as per the default automatic setup.
If I want to include that dll in 2 different projects, each of which providing a custom style for "MyControl" to give it a different look, where do I put those custom styles?
I thought I just had to have a Themes\Generic.xaml for each application, that defines the custom style, but having done this, it still ends up using the style defined in CustomControlLibrary.dll
You have CustomControlLibrary.dll which is the owner of MyControl. Inside that dll you have your themes defined. Any other project that may contain your dll doesnt haven to have themes defined.
Other projects may define their custom style for MyControl in their window resource for example.
Styles may be defined at any level. :)
Check this link out:
http://msdn.microsoft.com/en-us/library/ms745683.aspx
Solution will be to define specific style for each project and apply it correspondingly.
But keep in mind that you can create proper style "inheritance" by using BasedOn property. After all you should get a set of styles that you'll manage in MergedDictionaries:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/CustomControlLibrary;component/styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

Design templates in a class library at top scope

I use a class library (WPF user control library) to host some user controls which other (C#-) applications in the project solution consume. I want these controls to use XAML ControlTemplates residing at the top scope of the class library. The ControlTemplates do not have to be consumed outside the class library.
Here a template declaration:
<ControlTemplate TargetType="{x:Type Button}" x:Key="TemplateImageButtonSmall">
<Grid>
<Image Name="img" Source="/PSCommonUI;component/Images/Buttons/ButtonMinus_normal.png"/>
</Grid>
</ControlTemplate>
Then I have a user control in the class library, containing:
<Button Height="57" Margin="10,0,6,5" Name="button3" Template="{StaticResource TemplateImageButtonSmall}" Width="82">
In an application, I can use the App.xaml file for defining the templates. However, in a class library I don't have this option.
I have searched the web and found some answers including the use of a generic.xaml file, ComponentResourceKey, merging resource files and other stuff I find exaggeratedly complicated.
Also I read that theme definitions (resources in general) shouldn't reside in a class library.
But if I need some themes ONLY in this class library for the there hosted controls, how is best practice then?
Thanks in advance,
Julian
I am not sure what you meant, however, if you want child UIElements from a specific UIElement and below to use control templates, then you can define the templates in a resource dictionary and merge the dictionary into the top control that you want the dictionary to be visible to.
Edit:
The assembly just contains the classes and resources within it. It has no events of its own (e.g. OnApplicationLoaded).
A control's XAML can contain resources of its own (e.g. control templates) for consumption by itself and child controls and thus define default styling.
Your application can merge the resource dictionaries into any level of the tree (application, window, control, ...) and thus override defaults.
If you want the styling to be dynamic (overrable by importing resource dictionaries) then using the DynamicResource keyword your XAML. If your resource is defined in the same XAML and can not be overridden then use the StaticResource keyword.
Add a resource dictionary to your class library and define your resources (templates) there. It doesn't have to be generic.xaml.
Then in each user control or other .xaml file reference the resource dictionaries you require using Xaml similar to:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="... path to dictionary 1"/>
<ResourceDictionary Source="... path to dictionary 2"/>
<ResourceDictionary Source="... etc"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
You can then use resource keys from the merged dictionaries.

WPF Resource access from a different assembly if no App.xaml

I have am creating a WPF extension to an existing Win32 MFC client application. Within a UserControl located in my WPF class library, I am merging libraries as follows:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyResourceDLL;Component/dictionaries/styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
I also tried
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MyResourceDLL;Component/dictionaries/styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
In either case, I get the following XamlParseException:
System.Windows.Markup.XamlParseException
occurred
Message="MyResourceDLL;Component/dictionaries/styles.xaml'
value cannot be assigned to property
'Source' of object
'System.Windows.ResourceDictionary'.
Cannot locate resource
'ems.wpf.resources;component/dictionaries/styles.xaml'.
Error at object
'System.Windows.ResourceDictionary' in
markup file
'SARMaster.Maryln.EphemerisLib;component/getephemeriscontrol.xaml'
Line 9 Position 37."
I there a way I can load a relative DLL that is not referenced by main project?
I've been looking at the same issue recently. When compiling a Win32 CLR project the dependencies of the assemblies referenced by the MFC project aren't copied, so I simply set up a post-build event to copy the appropriate assemblies to the $(TargetDir).
Not ideal, but I believe it's by design.
I got the same problem and I found the solution. I needed to remove the Style of my ContentPresenter. This line was creating the XamlParseException:
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextStyle}"/>
</ContentPresenter.Resources>
And after fixing this error, I needed to do these steps to have something 100% working:
Here my projects:
StyleProject: the Class Library project that I want to use. It contains my styles
MainProject: the project that will use the styles
To do so:
Add the reference of my StyleProject inside my MainProject (see here)
Create a ResourceDictionary called MyStyle.xaml inside my MainProject
Add the different dictionaries of my StyleProject following this answer to MyStyle.xaml
Add MyStyle.xaml to the App.xaml using the following code
Code:
<ResourceDictionary Source="Resources/MyStyle.xaml"/>

WPF - Resource not loading from Generic.xaml

Themes\Generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="WPF Commons;component/Controls/Layout/Foo/FooItem.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Controls\Layout\Foo\FooItem.xaml:
<Style TargetType="{x:Type l:FooItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type l:FooItem}">
<Border>
<ContentPresenter ContentSource="Header" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If I copy the entire style into my usercontrol resources it works fine. But, if I don't, the usercontrol shows up empty. In Expression Blend 4, I right-clicked and chose Edit Template>, but it won't let me select Edit a Copy... which leads me to believe that something is severely wrong and the Generic.xaml isn't loading properly. I figure it's Generic.xaml because if I remove the MergedDictionary call and copy/paste the xaml style directly into Generic.xaml it still doesn't work.
I'm gonna take a wild guess that you altered your AssemblyInfo.cs file and either changed (or removed) the following line:
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
You need to tell your assembly about your ThemeInfo. :)
copying from my blog: http://zoomicon.wordpress.com/2012/06/10/what-to-do-if-generic-xaml-doesnt-get-loaded-for-wpf-control/
at the start of Properties\AssemblyInfo.cs you need (note this isn’t used/needed in Silverlight):
using System.Windows;
...
Mind you that if the project doesn’t show a Properties node in Solution Explorer, you have to either make a new project using the correct template (for a WPF custom control), or right click the project, select Properties, then press the Assembly Information button and enter some dummy values, then OK to create the Properties node (which also creates to a Properties subfolder and AssemblyInfo.cs file).
You can expand (drop-down) the special Properties node in solution explorer then to open AssemblyInfo.cs and add the above stuff if missing

How can i make a prefix so i can address a folder in xaml

I always have problems making new prefixes in xaml. Most of the time, i get the message that the URI cannot be found in the assembly. My setup:
I have a WPF project (in a solution with class libs and asp.NET projects) with a MainWindow.xaml file. The XAML starts with : Window x:Class="MainWindow" ... .
So as default, there's no namespace given to it. In that same project i made a folder "Folder". In that folder, i have resx-files. What i need to do is make a prefix in xaml so i can address those files. I was thinking of :
xmlns:p="clr-namespace:WpfApplication.Folder"
and then for my controls
<Label Content="{x:Static p:NameResxFile.KeyName></Label>
However, the prefix generates the "URI cannot be found in the assembly" error. I'm i just failing at making prefixes?
Thanks in advance.
EDIT
If you cannot make a namespace ref to a folder, what is happening here?
xmlns specifies namespaces, it does not bother with folders or files, if you need access to an external resource you can load it into your control's resources via ResourceDictionary.
There was something like this i think:
<Window.Resources>
<ResourceDictionary x:Key="ExternalRes" Source="Folder/File.xaml"/>
....
</Window.Resources>
To reference an element of resource dictionary you should add that dictionary to your control's Resources collection or register it in the App.xaml file. After that you could just use StaticResource extension to get access to the element. Your code will look like this:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Folder/NameResxFile.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<!-- ... -->
<Label Content="{StaticResource KeyName}"/>
Things get trickier if you want to put the resource dictionary to another assembly and reference it. For this purpose refer to PackURIs in WPF article.

Resources