if all Styles and Converters are stored in shared resource dictionary file (styles.xaml), and this file is used from various windows.
Is it possible, to pass a parameter to that file, and propagate that parameter to the converters?
I am looking for a way to pass a "origin" type parameter, so that the converters could be aware which place they are being used from? Just a hint of which window/grid is using the converter at the moment..
See this article for Converters with parameters. I assume you define the Converter resource in Resource dictionary.
http://www.switchonthecode.com/tutorials/wpf-tutorial-binding-converters
I wonder if something like this will work:
Add a reference to the System namespace in the declaration of each Window or UserControl where you want this.
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Then in your resources section set things up like this:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<sys:String x:Key="WinConvertParam">IDTextForThisWindow</sys:String>
</ResourceDictionary>
</Window.Resources>
Your binding syntax could then look something like this:
{Binding SomeProperty,
Converter={StaticResource thatConverterIWrote},
ConverterParameter={StaticResource WinConvertParam}}
...and your Convert or ConvertBack methods in your conversion classes then become aware of the Window that's using them, provided you vary the value of that <sys:String/> from file to file.
What do you think?
Related
I've been searching around if it is possible for an assembly to change the ResourceDictionary values from another assembly at runtime. So far I've found nothing.
HereĀ“s the deal. I have a UserControl that will work independently so it can be fit into different projects. My UserControl has its own Resources.xaml (Compiled as Resources).
I have a second assembly that it used as a setup tool for this user control. It basically just reads the UserControl Resources.xaml (which is working great) and then replaces the values of the Resources.Xaml. Trouble is, I cannot change the resource values.
Here's the code I use on my setup tool to read the ResourceDictionary:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Control;component/Configuration/Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
To change this values I've tried something like:
this.Resources.MergedDictionaries.First()["IsZoomable"] = false;
It does recognize the resources but it wont change it. Is it even possible to change the values of the dictionary of another assembly at runtime or will I need to create an external dictionary that can be acessed by both assemblies?
EDIT:
The user control contains the Resources.xaml. I've defined the Resources in this control like this:
<UserControl.Resources>
<ResourceDictionary Source="Configuration/Resources.xaml"/>
</UserControl.Resources>
The setup tool can acess this resources but I'm not able to change them. When I do, the user control still reads the old values. Resources are defined in the setup tool like so:
<Window.Resources>
<ResourceDictionary Source="pack://application:,,,/Control;component/Configuration/Resources.xaml"/>
</Window.Resources>
Yes, you can change the value of a resource at runtime.
Since you have merged the dictionary, you can change the value like this:
this.Resources["IsZoomable"]=false;
Make sure that the resource key matches the actual key.
If you have merged the dictionary in app.xaml, then you can use:
Application.current.Resources["IsZoomable"]=false;
In my application, I tend to reference my resource dictionaries using a relative path, like so:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Assets/ResourceDictionaries/SplashScreen.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
However, for one of the libraries I use in my application, (Fluent) the reference to the resource dictionaries I need are different (I believe they're called Pack URI's or something?):
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Fluent;component/Themes/Office2013/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<Color x:Key="{x:Static Fluent:MetroColors.ThemeColorKey}">#60327A</Color>
<vm:MainWindowViewModel x:Key="MainWindowViewModel" />
</ResourceDictionary>
</Application.Resources>
Is there a 'correct' way I should be referencing my resource dictionaries?
Pack URIs are required when the resource is in a different assembly than the one being compiled.
The Fluent URI references the Fluent assembly.
pack://application:,,,/Fluent;component/Themes/Office2013/Generic.xaml
In theory you could reference the current assembly, but I never use them unless I have to because they're such a pain to get right!
The difference is because a URI is used for accessing embedded resources, linked files, or loose files. However the URI may look different, depending on what type of resource is being accessed.
The "pack URI," with the three commas in it, is set up differently from the first URI, because the resource's source is a different type.
For more info, see this MSDN article.
So if I have a converter in the resource dictionary for my app like so:
<Application.Resources>
<ResourceDictionary>
<Converters:ColorToBrushConverter x:Key="ColorToBrushConverter" />
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionaries/GraphViewerBrushes.xaml" />
<ResourceDictionary Source="ResourceDictionaries/ColorPickerResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
How can I reference the converter from within one of the external xaml files? or is this not possible? i know i could just reinstance another converter there, but that seems wasteful.
You can use DynamicResource instead of StaticResource to reference the converter. This will cause it to look up the resource dynamically, which should succeed as it's part of the Application resources.
That being said, I typically just create another instance, as it is simpler, and a converter has very, very little overhead to create (since it should have no state).
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.
Here's my 'sample code', including what I'm trying to do. Obviously, it doesn't work at the moment, but is there any way I can make it work?
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
>
<System:String x:Key="ProductName">Foo</System:String>
<System:String x:Key="WindowTitle">{ProductName} + Main Window</System:String>
</ResourceDictionary>
The only way to add a computed string to a ResourceDictionary in this way is to create a MarkupExtension. Your MarkupExtension would be used like this:
<ResourceDictionary ...>
<sys:String x:Key="ProductName">Foo</sys:String>
<local:MyStringFormatter
x:Key="WindowTitle"
StringFormat="{0} Main Window"
Arg1="{StaticResource ProductName}" />
</ResourceDictionary>
This assumes you have created a MarkupExtension subclass in your "local" namespace named MyStringFormatterExtension that has properties named "StringFormat", "Arg1", "Arg2", etc, and has a ProvideValue() method that does the obvious.
Note that as Aran points out, a Binding using StringFormatter would be a more common way to achieve the same effect, and is generally the better design. The tradeoff is it would not allow the result to be used as part of a ResourceDictionary.