Accessing ResourceDictionary from WPF UserControl - c#

I'm trying to access a resource dictionary in a UserControl code-behind via C# and I'm having little success.
Merged Dictionary:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/BiometricDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Embedded Dictionary:
<UserControl.Resources>
<BitmapImage x:Key="imageDefault">/Resources/Images/default_thumb.png</BitmapImage>
<BitmapImage x:Key="imageDisconnected">/Resources/Images/disconnect_thumb.png</BitmapImage>
<BitmapImage x:Key="imageFailed">/Resources/Images/failed_thumb.png</BitmapImage>
<BitmapImage x:Key="imageSuccess">/Resources/Images/success_thumb.png</BitmapImage>
</UserControl.Resources>
Code behind:
var resourceDictionary = new ResourceDictionary();
resourceDictionary.Source = new Uri("/Resources/BiometricDictionary.xaml", UriKind.Relative);
I've tried all of the examples and helpful tips but coming up short. Right now, success would be the ability to load the dictionary. Any suggestions?

To access one of your UserControl's XAML resources in your codebehind, all you need to do is access the Resources property of the UserControl. Something like this:
BitmapImage myImage = (BitmapImage)this.Resources["imageDefault"];
Though, the preferred method is to use FindResource(), which will search the entire logical tree for a match to the key, rather than just the object it is called on.
BitmapImage myImage = (BitmapImage)this.FindResource("imageDefault");

Try to remove the forward slash infront of your location. The only time you should use /Resources is if you have to go up a library first. like ../Resources
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/BiometricDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Hope this helps you.

So, you have a ResourceDictionary defined in a UserControl's assembly, and would like to access it from that UserControl's code-behind?
You should be able to. However, if the code you listed is in the constructor, you may not have access to the resource dictionary (might not be loaded yet). Try adding that same code to your UserControl's "loaded" event, and see if that works. If you're simply trying to access a resource, such as a style or template, using the "FindResource" or "TryFindResource" functions directly from your class should work as well (i.e. you don't need to have an object of type "ResourceDictionary").
Hope that helps!

d'Oh...after compiling to the local bin so that references are relative, I implemented the pack URI solution found here: ResourceDictionary in a separate assembly and then FindResource(x:key value here).
#PeterAllenWeb, #Pwninstein, thanks for your quick responses and getting me thinking again.

Related

Styles from resource dictionary not found in user control

I have a resource dictionary with a bunch of styles that I am linking too in my user controls like so:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Theme/ThemedResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
This all works fine during runtime.
However I get a recurring problem in that one of the styles in the resource dictionary 'cannot be found' in whichever user control is the most recent, until the solution is rebuilt. This error will then appear again after I stop the debugging process, and again will disappear with a rebuild.
I don't think this is linked to a specific style, as when I add new styles the style that can't be found seems to change.
Any ideas how I can stop this from happening?
You have used a Relative URI, so it will looks for your resource file in a somewhere that you used your UserControl. It can't find you resource file because your resource file is not in the AbsolutePath.
AbsolutePath = CurrentPath (r.g Where you used your UserControl) + RelativePath
so Use an AbsolutePath:
<ResourceDictionary Source="pack://application:,,,/{YourAssemblyName};component/Theme/ThemedResources.xaml" />

The good practice for defining a reusable resources in WPF

I've been writing a CAD-style program in .Net, for this I have to have a lot of Brushes and Custom DashStyles.
So far I have defined them in a static class. for example:
public static readonly Brush GridBrushInModel = Brushes.DarkGray;
Now I can use the brush whenever I want. I have also Freezed them though.
My question is, is this the way this should be done? Or there are better ways? For example defining in ResourceDictionary? How it is done?
Shared resources in a WPF application are typically stored as a ResourceDictionary. Each dictionary should have its own XAML file (if you wish to split up your resources).
They are pretty easy to define:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="MyCoolBrush" Color="Black"/>
</ResourceDictionary>
Note that I gave the element a x:Key attribute. This is what you use to reference the resource later.
Finally, you have to merge the dictionary into the using code. This can be done at any level, though its most commonly done in the Window.Resources or in App.xaml.
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/MyBrushes.xaml"/>
</ResourceDictionary.MergedDictionaries>
...
</ResourceDictionary>
</Window.Resources>
Once you have them, you can reference them in XAML like this:
<Grid Background={StaticResource MyCoolBrush}/>

What kind of "Key" do I need to supply when loading Resource Dictionaries?

In trying to set a default ResourceDictionary I receive the following warning:
The designer does not support loading dictionaries that mix
'ResourceDictionary' items without a key and other items in the same
collection. Please ensure that the 'Resources' property does not
contain 'ResourceDictionary' items without a key, or that the
'ResourceDictionary' item is the only element in the collection.
This is the code that I am using in my App.xaml file, that received the above warning:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Lang.en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
This is the exact same code that I've used to set a ResourceDictionary in Visual Studio 2008. I am now using VS 2010. What Key do I need to provide this ResourceDictionary for it to work correctly?
This is the line in my MainWindow.xaml that I am currently testing along with this code:
<MenuItem Header="{DynamicResource new_test}" />
Since you haven't posted your complete XAML file, i suspect there are other resources apart from merged dictionary in your resources section.
As per MSDN -
It is legal to define resources within a ResourceDictionary that is
specified as a merged dictionary, either as an alternative to
specifying Source, or in addition to whatever resources are included
from the specified source. However, this is not a common scenario; the
main scenario for merged dictionaries is to merge resources from
external file locations. If you want to specify resources within the
markup for a page, you should typically define these in the main
ResourceDictionary and not in the merged dictionaries.
Try moving other resources in separate resource dictionary and make sure all other resources have x:Key set on them -
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Lang.en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<ContextMenu x:Key="MyContextMenu"/>
</ResourceDictionary>
</ResourceDictionary>
</Application.Resources>
Use resource file for translations. Its better than resource dictionary.
Here is an example:
Set prefix like this for usage in xaml.
xmlns:const="clr-namespace:FileExplorer.Properties"
Resources are located in properties.
To use them in XAML you will need following:
<TextBox Text="{x:Static const:Resources.Window_Title_String}"/>
If you have different languages then create for each language own resource file following naming convention.
For example:
Resources.resx (this will be default)
Resources.de-DE.resx (this is for german)
Now you just have to set current culture to german for your app to be on german and the proper resource file will be used automatically.
Like this in Main method:
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");

WPF Prism - Where to put Resources?

I have a prism application and various modules. I am wondering where is the best place to locate resources such as styles, brush, controltemplates, datatemplates?
Should I make one single resource dictionary and put everything there? Should each module have their own resources? Or each view? I would like to follow the Prism goal of keeping everything modular, but also I dont see the point in re-declaring the same resources in every module...
I develop application with Prism, and I use technique very close to described in Prism's manual. There is YourApplication.Infrastructure project, where you usually place all your shared interfaces etc. So:
I just add project YourApplication.Resources
Create there folder Themes
Create separate xaml file in Themes folder for each group of resources (like Generic.WPF.xaml for standard WPF controls' styles, Generic.Brushes.xaml for brushes etc.)
Create file Themes\Generic.xaml (exactly with this name, it will add huge benefits in the future) with content like
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Generic.Brushes.xaml"/>
<ResourceDictionary Source="Generic.WPF.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Now you can add those resources in any module (you have separate project for it, right?) by adding reference to YourApplication.Resources to that project and adding to your view's xaml:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/YourApplication.Resources;component/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- Put your not shared resource here -->
</ResourceDictionary>
</UserControl.Resources>
I don't know, maybe this way has some problems, but it works, and works well for me. If anybody can comment somehow this way (pros/cons) - I will be very happy to hear it!
Application-wide resources I usually put in a ResourceDictionary, which is added to either App.xaml or StartupWindow.xaml
Resources for a specific View are usually located with the View. For example, a UserControl that is being used for a CalendarView will contain any custom resources for the Calendar, such as calendar-specific brushes, styles, templates, etc.
I usually don't see a reason to make module-wide resources, but if I ever do I'd have a ResourceDictionary for the Module which can be loaded into the app's merged dictionaries at runtime, or included in individual Views in the Module.
I would like to share some new knowledges. I am using #chopikadze approach. And it is really cool approach. Thanks to you!
However, if you do not want write every time for each control these piece of code:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/YourApplication.Resources;component/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- Put your not shared resource here -->
</ResourceDictionary>
</UserControl.Resources>
Then you can just declare <ResourceDictionary/> in App.xaml of your Bootstrapper like that:
<Application.Resources>
<ResourceDictionary Source="pack://application:,,,/YourApplication.Resources;component/Themes/Generic.xaml"/>
</Application.Resources>

In WPF how do I reference a static resource that is defined in a different XAML file?

In WPF how do I reference a static resource that is defined in a different XAML file? It's in the same project.
The other XAML file will need to be a resource dictionary. You merge it into the current file using the MergedDictionaries property of the current ResourceDictionary. See Merged Resource Dictionaries on MSDN. Their example:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="myresourcedictionary.xaml"/>
<ResourceDictionary Source="myresourcedictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
Then within that Page object you can reference static resources defined in myresourcedictionary.xaml or in myresourcedictionary2.xaml.
"different XAML file" could mean a few different things:
App.xaml: Resources are automatically included in the resource tree of anything that's opened so you don't need to do anything extra.
Window or Page .xaml: Resources can be accessed by any child of an instance of the object like a UserControl that is used in a Window.
ResourceDictionary: Needs to be explicitly merged into the resource tree somewhere above where it is used. This can be App.xaml, Windowxx.xaml, or some lower level element. Use ResourceDictionary.MergedDictionaries to do this.
There are also lots of alternate ways to specify the path but this is the simplest:
<Window>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/MyResourceDict.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>

Categories