Merge DictionaryResource from Application in a ClassLibrary - c#

I have a Windows Phone 8.1 solution that has a Standard Application Project and a Class Library Project. The idea is that I can, somehow, StaticResources down do the ClassLibrary so it can override the existing ones. I'll give you an example:
In my ClassLibrary I have a ClassLibraryDictionary.xaml with the following code:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ClassLibraryTest">
<SolidColorBrush x:Key="MyButtonColor" Color="#FF0000FF" />
</ResourceDictionary>
And the idea is that in my MainApplication I could have a Dictionary.xaml with the same StaticResource Key, and pass it to my ClassLibrary so it can override the default property, something like:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MainApplicationTest">
<SolidColorBrush x:Key="MyButtonColor" Color="#00FF00FF" />
</ResourceDictionary>
And passing it in code:
var mainAppDictionary = new ResourceDictionary();
mainAppDictionary.Source = new Uri("/using:MainApplicationTest;component/MainApplicationDictionary.xaml", UriKind.RelativeOrAbsolute);
classLibraryTest.SetResourceDictionary(mainAppDictionary);
The problem here is that I can't seem to use the ResourceDictionary instance in my ClassLibrary, and I'm not even sure this is the best way to do this.
So, how could I solve this?

I found out how to this and it is actually simple. The path I was using was not the correct one, so to sum it all up, the solution in XAML, if you were to do it in the App.xaml (in the MainApp) looks like this:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx://Common/yourclasslibraryname/ClassLibraryDictionary.xaml"></ResourceDictionary>
<ResourceDictionary Source="/Dictionary1.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
If you want to set it in code directly in the ClassLibrary you can do something like this:
In the MainApp.xaml.cs
myClassLibrary.MergeAllDictionaries(App.Current.Resources);
And in the ClassLibrary:
public void MergeAllDictionaries(ResourceDictionary appDictionary) {
// First copy all keys from MainApp to a new Dictionary
ResourceDictionary mainDictionary = new ResourceDictionary();
foreach(var keys in appDictionary.MergedDictionaries) {
foreach(var keys1 in keys) {
mainDictionary.Add(keys1.Key, keys1.Value);
}
}
// Then clear all
appDictionary.Clear();
// Get the ClassLibrary dictionary
ResourceDictionary classLibraryDictionary = new ResourceDictionary();
classLibraryDictionary.Source = new Uri("ms-appx://Common/yourclasslibraryname/ClassLibraryDictionary.xaml", UriKind.RelativeOrAbsolute);
// First add the ClassLibrary keys and values
appDictionary.MergedDictionaries.Add(classLibraryDictionary);
// Then add the old values, so that they overwrite the ClassLibrary ones
appDictionary.MergedDictionaries.Add(mainDictionary);
}

Related

Different ways of using ResourceDictionary.MergedDictionaries

I was going through some code in our product and saw some colleagues using ResourceDictionary.MergedDictionaries in a way I had not seen it used before:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<toolTips:ToolTips />
<styles:ControlStyles />
<icons:IconDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
tooltips:ToolTips and all the other elements in the MergedDictionaries are ResourceDictionaries.
The regular way of using these according to the internet is to use <ResourceDictionary Source="uri to your xaml file"/>.
So is there any practical difference between both?
If this way works why isn't it used more often as it plays well with code completion?
I've used ResourceDicionary this way only once on a big project and it was benefical in my situation.
Suppose that you have ResourceDictionary in MyDictionary.xaml file.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="YourNamespace.MyDictionary">
</ResourceDictionary>
You can add an x:Class attribute to the ResourceDictionary element and specify the fully qualified name of the code-behind class.
Let's create MyDictionary.xaml.cs with class MyDictionary (name can be different from the name of the xaml file).
public partial class MyDictionary
{
public MyDictionary()
{
InitializeComponent();
}
}
A class must be a partial class. The constructor must be added to the class and InitializeComponent method must be called. The InitializeComponent method will be automatically generated for the class if you set the x:Class attribute in MyDictionary.xaml
Now you can reference MyDictionary in MergedDictionaries
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
If you add some DataTemplate into MyDictionary.xaml you can create event handlers in code-behind (handlers will be automatically generated by VS)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="YourNamespace.MyDictionary">
<DataTemplate x:Key="MyTemplate">
<Button Click="Button_Click"/>
</DataTemplate>
</ResourceDictionary>
Code-behind:
public partial class MyDictionary
{
public MyDictionary()
{
InitializeComponent();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
// custom logic
// edit another element, etc.
}
}
If the class is inherited from the ResourceDictionary class then other resources can be accessed from the code-behind.
Example of usage of data template defined in MyDictonary:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyDictionary/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl ContentTemplate="{StaticResource MyTemplate}"/>
</Grid>
From my point of view the biggest advantages are that you can encapsulate logic into separated files (it's easy to maintain and add new features in big projects) and avoid referencing ResourceDictionaries by <ResourceDictionary Source="uri to your xaml file"/>.

MVVM - The name does not exist in the name space

I am trying to start a MVVM pattern and I have this structure:
App.xaml:
<Application x:Class="StereoVisionApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StereoVisionApp"
StartupUri="MainView.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:MainViewModel x:Key="StereoVisionApp.MainViewModel"/>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
MainViewModel.cs:
namespace StereoVisionApp.ViewModels
{
class MainViewModel
{
public MainViewModel()
{
}
}
}
I have an error on this line:
<local:MainViewModel x:Key="StereoVisionApp.MainViewModel"/>
Says:
The name "MainViewModel" does not exist in the namespace
"clr-namespace:StereoVisionApp". StereoVisionApp C:\Users\Me\source\repos\StereoVisionApp\StereoVisionApp\App.xaml
I have tried restarting million times. any help?
In Visual Studio, when you create a new folder in the project at creates a new namespace named projectname.foldername by default. (in your case: StereoVisionApp.ViewModels). All the files inside it automatically takes that namespace.
You can either:
Change the namespace in MainViewModel.cs
or
Add the new namespace to App.xaml like this:
add this in Application header in App.xaml
xmlns:vm="clr-namespace:StereoVisionApp.ViewModels"
Then use it like this:
<vm:MainViewModel x:Key="StereoVisionApp.MainViewModel"/>
Also note that the x:Key value is a string of your choice (doesn't have to be an exact location, so you can actually write:
<vm:MainViewModel x:Key="mainViewModel"/>
The x:Key value is for future reference only.

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

WPF localization with ResourceDictionary

At the moment I integrate the current strings like this:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="lang/Dictionary.en-US.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Is there a possibility to do this dynamically in my code behind files?
Sure you can just do something like:
var res = new ResourceDictionary {Source = new Uri("somepath")};
this.Resources.MergedDictionaries.Add(res);
Note: This is off the top of my head on not tested but it should work

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