How to use resource dictionaries in custom control library? - wpf

I've created a resource dictionary with some frequently used brushes.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="GrayColor1" Color="#f2f2f2"/>
<SolidColorBrush x:Key="GrayColor2" Color="#e5e5e5"/>
<SolidColorBrush x:Key="GrayColor3" Color="#d9d9d9"/>
...
</ResourceDictionary>
I want to use them in many controls in the custom control library, but I didn't find any way to make them available to the controls.
In a normal app I will put them in App.xaml, but in a library there is no App.xaml file.
So what is the way to use resource dictionary in a library?
I already tried without success to merge the dictionary into /Themes/Generic.xaml as this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyControls;component/DefaultBrushes.xaml"/>
<ResourceDictionary Source="/MyControls;component/Styles/CustButton.xaml"/>
<ResourceDictionary Source="/MyControls;component/Styles/CustTextBox.xaml"/>
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
But referencing the resources results in a null reference (seems that in Generic.xaml can be merged only control templates).

You have to merge them in each control, or in the most top control if you have nested controls.
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://Application:,,,/MyControls;component/Styles/CusTextBox.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>

You can still create your merged dictionaries in your applications App.xaml, but in your controls library where you want to access those brushes, try using DynamicResource instead of StaticResource.
Background="{DynamicResource GrayColor1}"

Related

ResourceDictionary administration

The main WPF project has resources defined in App.xaml.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/Views;component/Themes/Standard.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Here Views is another project which contains all kinds of UserControls.
This works all right, except that in the UserControls xaml the styles of Standard.xaml are not recognized because in this project App.xaml is not loaded.
So, compile time warnings like Resource cannot be resolved are shown.
It can be fixed by adding
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/Views;component/Themes/Standard.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
to all UserControl files, but I would like to add this only one time somewhere in this project that doesn't contain App.xaml.
I can also ignore the warnings of course.
Inheritance for UserControl is when I understand correctly only possibe in a .cs file, not with a .xaml file.
Any other suggestions?

Style based on StaticResource previously defined is not found at runtime

I'm using Telerik's RadControls for WPF with implicit styling. The following style is defined in Themes/Windows8/Telerik.Windows.Controls.RibbonView.xaml:
<Style TargetType="telerikRibbonView:RadRibbonView" x:Key="RadRibbonViewStyle">
...
</Style>
My own styles and the Telerik default ones get merged like this in the assembly Lib.Windows.Controls in the folder Themes:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Windows8/Telerik.Windows.Controls.RibbonView.xaml" />
<ResourceDictionary Source="MyTheme/TelerikCustomizations.xaml" />
<ResourceDictionary>
<!-- avoid optimization -->
<Style TargetType="{x:Type Rectangle}" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
And in TelerikCustomizations.xaml I define the following (empty, for testing purposes) style:
<Style x:Key="MyThemeRadRibbonViewStyle" TargetType="{x:Type telerik:RadRibbonView}" BasedOn="{StaticResource ResourceKey=RadRibbonViewStyle}" />
Which results in the following exception at runtime:
'Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception.' Line number '4' and line position '42'.
{"Cannot find resource named 'RadRibbonViewStyle'. Resource names are case sensitive."}
Which led me to the following debugging statements in MyView.xaml.cs:
public ShellView()
{
var baseStyle = FindResource("RadRibbonViewStyle");
var inherited = FindResource("MyThemeRadRibbonViewStyle");
InitializeComponent();
}
Now the thing is: The exception is thrown on the second FindResource call. With the exact same message. However the RadRibbonViewStyle is clearly found in the first line of the constructor.
If it matters, the merged dictionary is actually merged in App.xaml a second time.
I'm sure I'm missing something obvious, but I can't figure out what.
App.xaml
<Application x:Class="TestClient.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Views/ShellView.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Lib.Windows.Controls;component/Themes/MyTheme.xaml" />
<ResourceDictionary>
<!-- added to avoid optimization -->
<Style TargetType="{x:Type Rectangle}" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
App.xaml.cs does not overwrite the constructor. In fact it does not do anything.
Update
If I merge the Telerik dictionaries in TelerikCustomizations.xaml instead of merging them in yet another dictionary (MyTheme.xaml), the exception disappears.
However, I'd still like to know why this happens.
You need to merge in the Windows8/Telerik.Windows.Controls.RibbonView.xaml in your MyTheme/TelerikCustomizations.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Windows8/Telerik.Windows.Controls.RibbonView.xaml" />
<ResourceDictionary>
<Style x:Key="MyThemeRadRibbonViewStyle" TargetType="{x:Type telerik:RadRibbonView}" BasedOn="{StaticResource ResourceKey=RadRibbonViewStyle}" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
And now you can use/merge this dictionary wherever you want.
You need to do this because StaticResource is not working between "sister" MergedDictionaries so you cannot reference a resource which was merged on the same level because the StaticResource looks only backwards to the direct parents:
From MSDN:
XAML resource references within a particular resource dictionary must
reference a resource that has already been defined with a key, and
that resource must appear lexically before the resource reference.
Forward references cannot be resolved by a XAML resource reference
But when using MergedDictionaries:
In the resource-lookup sequence, a MergedDictionaries dictionary is
checked only after a check of all the keyed resources of the
ResourceDictionary that declared MergedDictionaries.

How can I import a deep hierarchy of merged dictionaries with 1 ResourceDictionary?

I am attempting to merge in dictionaries from a dependent class library project, but the resource keys can't be found. Note: I am using this Connect bug workaround from Microsoft which is supposed to allow the framework to search deep enough to find the nested resources. This does not appear to be working.
Example of Failure
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyApplication.ControlLibrary;component/ResourceDictionaries/ResourceLibrary.xaml" />
<ResourceDictionary>
<Style TargetType="{x:Type Line}" /> <!-- workaround from MS to allow for this -->
<Main:AppBootstrapper x:Key="bootstrapper" /> <!-- CaliburnMicro bootstrapper, unsure if this is relevant -->
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Inside ResourceLibrary.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DefaultColorTheme.xaml" />
<!-- ...snip... -->
<ResourceDictionary Source="TransitionControl.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
When doing this, it cannot find the resource keys. If I merge each dictionary in manually from that class library, it works fine. This, IMO, begins to defeat the purpose of abstracting resources out to an external assembly.
Example of Success
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyApplication.ControlLibrary;component/ResourceDictionaries/DefaultColorTheme.xaml" />
<ResourceDictionary Source="/MyApplication.ControlLibrary;component/ResourceDictionaries/Images.xaml" />
<ResourceDictionary Source="/MyApplication.ControlLibrary;component/ResourceDictionaries/FontIcons.xaml" />
<ResourceDictionary>
<Style TargetType="{x:Type Line}" />
<Main:AppBootstrapper x:Key="bootstrapper" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Have I placed the dummy implicit style in the wrong place? Something isn't adding up here. Thanks for looking.
I've learned this the hard way by playing around with it for 3 days.
do not make really deep structures. Have a main dictionary that is just using other dictionaries. The app is not supposed to access anything from the others.
But the crucial thing is to reference them in the right order. it wont work if you load a RD where one of it's contents use something from another one that is not already loaded. The order is truly crucial.
Using WPF Inspector will help you a lot since it makes it possible to track everything donw in an WPF app.

Using Styles in merged ResourceDictonaries in Silverlight 5

I've got a bunch of styles in my app.xaml and they are all being used just fine in my pages within my SL5 app. I'd like to move these styles to multiple resource dictionaries to make it more manageable and consumable.
First I copied a style to a new resource dictionary in the /Styles/ButtonStyles.xaml page in my project... a snippet looks like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="RegistrationsRolloverImage" TargetType="Button">
<Setter Property="Template">...</Setter>
</Style>
<Style x:Key="FinancialLedgerRolloverImage" TargetType="Button">
<Setter Property="Template">...</Setter>
</Style>
</ResourceDictionary>
Next I added the following to my App.xaml:
<ResourceDictionary x:Key="MergedStyles">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/ButtonStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
It forced me to add a x:key to the ResourceDictionary tag as I kept getting a build error. Now it builds, but the buttons that use the style aren't getting the style. In fact I'm getting a JS error that it can't find a style with the name of the two styles in my resource dictionary. They work just fine if they are in the App.xaml, but not if they are in seperate resource dictionary. I reflected the generated DLL and can see the styles/buttonstyles.xaml in the DLL.
At a loss... and can't figure out what's wrong. Ideas?
Are they within the same project? Try something more like this in your app.xaml;
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/YourResDictionaryContaining.Proj.Name;component/Styles/ButtonStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
I have to do this to have consolidation of resourcedict's stored in one project, and then add that to the app.xaml of each other project to make them available globally. Currently I run about 6 Resource Dicts acros 20 projects in the same solution this way and it works great.
In the full App.xaml sample you want use "local" resources.
But when you have "local" resources and you want to merge a resource directory the systax a little bit different.
Try it like this:
<Application ...>
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/ButtonStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="BaseTextBlock" TargetType="TextBlock">
...
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

WPF ResourceDictionary and DynamicResource

i am new to WPF so maybe this will be "noob" question but i can't find answer to it (and it seems so easy)...
well i am programing WPF app and i want to use smth similar to css for webpages, so i found ResourceDictionary and tried to use it...
I have main window in which i create Frame and on click some UserControl is loaded to that same Frame.I include my ResourceDictionary (root/style/Styles.xaml) to my main window like this:
<Window.Resources>
<ResourceDictionary x:Key="styles" Source="style/Styles.xaml" />
</Window.Resources>
in which i have:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="ProductsRequired" TargetType="{x:Type Label}">
<Setter Property="Height" Value="28" />
...
I don't use it on my main window but want to use it on my UserControls, which are loaded to that main window and i try to use it like this:
<Label Name="product1" Style="{DynamicResource ProductsRequired}" />
Warning i am getting all the time is: The resource "ProductsRequired" could not be resolved.
I even tried including Styles to my UserControl
<UserControl.Resources>
<ResourceDictionary x:Key="styles" Source="../style/Styles.xaml" />
</UserControl.Resources>
and nothing happens...
Well my question is long but i wanted to be clear... :)
P.S. all that logic works in C# code btw
private ResourceDictionary myStyles = new ResourceDictionary();
Style ProductsRequired = myStyles["ProductsRequired"] as Style;
product1.Style = ProductsRequired;
This won't do, you add a resource dictionary as a resource when you need to add it to the resources, it cannot be accessed like this. You need to add it to the MergedDictionaries (See MSDN for usage examples!).
are you referencing the correct assembly?
for example:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/SecurityManagerResources;component/DictionarySecurityResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
You need to do this
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="style/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>

Resources