WPF – Insert Resource Dictionary in C# into XAML - c#

By this way I can access XAML resources in C# code:
var resource = new ResourceDictionary
{
Source = new Uri("/myAssemblyName;component/Themes/MyStyle.xaml", UriKind.RelativeOrAbsolute)
};
I thinking about a reverse approach. I would like define resource dictionary in C# code like this:
public class MyColors : ResourceDictionary
{
public MyColors ()
{
this.Add("MyGreen", Color.FromRgb(10, 211, 12)); // this["MyGreen"] = Color.FromRgb(10, 211, 12);
}
}
And then include this resource dictionary into XAML style file like this:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyColors.cs" />
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="MyGreenBrush" Color="{StaticResource MyGreen}" />
</ResourceDictionary>
The question is about possibility of including resource dictionary into XAML file. Because presented approach not working – error: Unexpected project file type at …\MyColors.cs.

You need to construct your created class inside MergedDictionaries
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<yourClassXmlNamespace:MyColors/>
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="MyGreenBrush" Color="{StaticResource MyGreen}" />
</ResourceDictionary>

you should build the dictionary in XAML
this will look as follows
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF_ScratchPad">
<Color x:Key="MyGreen">#0ad30c</Color>
</ResourceDictionary>
then as your are correctly doing you merge the controls dictionary
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyColors.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
If you really need to create your dictionary in code then you would merge it as follows
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<yourxmlns:MyColors/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
once you have added the dictionary to the control you don'[t need to instantiate a separate instance of the dictionary to access it instead just call TryFindResource as this keeps the override structure intact

Related

XAML: How can I change the source of a specific ResourceDictionary

<Application x:Class="CDesign.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CDesign"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary x:Name="ThemeDictionary">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/AppStyles;component/Resources/Icons.xaml"/>
<ResourceDictionary Source="pack://application:,,,/AppStyles;component/Resources/IconsNonShared.xaml"/>
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<!-- Accent and AppTheme setting -->
<ResourceDictionary x:Uid="Accents" x:Name="Accents" Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary x:Uid="BaseTheme" x:Name="BaseTheme" Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
How can I change the source of a specific ResourceDictionary inside ResourceDictionary.MergedDictionaries based on the ResourceDictionary's x:Name/x:Uid?
Thanks.
I don't think you can do that based on x:Name or x:Uid. ResourceDictionary does not define mappings for those markup properties. For example, UIElement is marked with UidPropertyAttribute("Uid") and so UIElement marked with x:Uid attribute will have that value available as Uid property. Same story with x:Name. But ResourceDictionary does not define such mappings, and so those properties are effectively lost after xaml is parsed and compiled.
Now, what you can do instead? One option that comes to mind is to use your own attached property to assign resource dictionary an identifier. Unfortunately, ResourceDictionary does not inherit from DependencyObject, and so we cannot use attached properties on it.
However, there is one hack with which we can abuse attached property syntax and still reach the goal. Let's define fake attached property like this:
public static class ResourceDictionaryExtensions {
private static readonly Dictionary<ResourceDictionary, string> _mapping = new Dictionary<ResourceDictionary, string>();
public static void SetName(ResourceDictionary element, string value) {
_mapping[element] = value;
}
public static string GetName(ResourceDictionary element) {
if (!_mapping.ContainsKey(element))
return null;
return _mapping[element];
}
}
Note that this definition is different from usual attached property. First, there is no attached property at all. Second, two methods GetName and SetName do not accept DependencyObject (like methods associated with attached properties do), but ResourceDictionary. However, because we have GetName and SetName methods - we can use attached property syntax, like this:
<Application.Resources>
<ResourceDictionary x:Name="ThemeDictionary">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/AppStyles;component/Resources/Icons.xaml"/>
<ResourceDictionary Source="pack://application:,,,/AppStyles;component/Resources/IconsNonShared.xaml"/>
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<!-- Accent and AppTheme setting -->
<ResourceDictionary local:ResourceDictionaryExtensions.Name="Accents" Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary local:ResourceDictionaryExtensions.Name="BaseTheme" Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Even though target object (ResourceDictionary) is not dependency object, and that property is not attached property at all.
Now it's easy to modify source of target dictionary:
var dict = Application.Current.Resources.MergedDictionaries.First(c => ResourceDictionaryExtensions.GetName(c) == "Accents");
dict.Source = new Uri("path to the new dictionary");

wpf modern-ui How can I choose a theme in code behind?

In codeplex's mui, the app.xaml goes like this
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.xaml" />
<ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/modernui.light.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
but how can I choose the FirstFloor.ModernUI;component/Assets/modernui.light.xaml" in replace of FirstFloor.ModernUI;component/Assets/modernui.light.xaml" in code behind every time I run the program?
The ModernUI source code comes with a sample application that shows you how to do exactly what you ask.
The library has an AppearanceManager class. Set the current instance ThemeSource property:
AppearanceManager.Current.ThemeSource = AppearanceManager.LightThemeSource;

How to place XAML-only resources in a DLL (Reference) file to be used by WPF applications?

My WPF applications are reaching the level of complexity at which it becomes desirable to place some of the code and other resources inside a Reference file (*.dll).
I am sure I can figure out how to do this, by following the myriad applications out there.
In this particular case, however, the files are two, XAML:
Can somebody please provide an example on how to expose or publish the XAML resources? Are *.cs files required?
TIA
The XAML file outlined by #HighCore should look like this:
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
XAML ResourceDictionaries do not generate classes. I'm not sure why you would expect such thing.
Simply move the needed ResourceDictionary definitions to a separate assembly then use the Pack URI Syntax to merge these resources to your application's Resources in app.xaml:
<Application ....>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

ResourceReferenceKeyNotFoundException declared on Dictionary.xaml

I have an ObjectDataProvider declared on a dictionary:
<ObjectDataProvider x:Key="Resources"
ObjectType="{x:Type const:CultureResources}"
MethodName="GetResourceInstance"/>
And I have a class that wants to find it like this:
m_provider = (ObjectDataProvider) App.Current.FindResource("Resources");
But when it tries to find the Resource, it launches the error
ResourceReferenceKeyNotFoundException
And can't find my resource... Here you have an image on how my project is divided:
The Default.xaml is my default dictionary.
So, why I can't find my Resources element defined on my dictionary?
I need to answer my question, because it was such a weird thing...
At first, I need to say that I had to add my Dictionary.xaml to my App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../themes/Default.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
For some reason, it wasn't enough to call it on my MainWindow.xaml. So I erased it from my MainWindow.xaml and added it to App.xaml, but I couldn't have them inserted in both sides. That was the part that I couldn't see clearly...

Changing the Theme at Run Time

I use JetPack theme and set it from App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Assets/Styles/Brushes.xaml"/>
<ResourceDictionary Source="Assets/Styles/Fonts.xaml"/>
<ResourceDictionary Source="Assets/Styles/CoreStyles.xaml"/>
<ResourceDictionary Source="Assets/Styles/Styles.xaml"/>
<ResourceDictionary Source="Assets/Styles/SdkStyles.xaml"/>
<ResourceDictionary Source="Assets/Styles/ToolkitStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
How can i set theme from code-behind and change theme at run time?
The Silverlight Toolkit base Theme control provides support for changing a theme at runtime. Unfortunately, the Application Themes like the JetPack Theme are no Toolkit themes (ask Microsoft why). So you'd have to convert them yourself. A look at the Toolkit themes sources helps us to figure out how:
public class JetPackTheme : Theme
{
private static Uri ThemeResourceUri = new Uri("/MyComponent;component/JetPackTheme.xaml", UriKind.Relative);
public JetPackTheme() : base(ThemeResourceUri) { }
public static bool GetIsApplicationTheme(Application app)
{
return GetApplicationThemeUri(app) == ThemeResourceUri;
}
public static void SetIsApplicationTheme(Application app, bool value)
{
SetApplicationThemeUri(app, ThemeResourceUri);
}
}
Now, assuming your resources are in a folder called JetPackTheme, here is JetPackTheme.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyComponent;component/JetPackTheme/Brushes.xaml"/>
<ResourceDictionary Source="/MyComponent;component/JetPackTheme/Fonts.xaml"/>
<ResourceDictionary Source="/MyComponent;component/JetPackTheme/CoreStyles.xaml"/>
<ResourceDictionary Source="/MyComponent;component/JetPackTheme/Styles.xaml"/>
<ResourceDictionary Source="/MyComponent;component/JetPackTheme/SdkStyles.xaml"/>
<ResourceDictionary Source="/MyComponent;component/JetPackTheme/ToolkitStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Now you should be able to use a JetPackTheme control in your application:
<myCmp:JetPackTheme x:Name="myTheme">
<SomeNeatStuff>
...
</SomeNeatStuff>
</myCmp:JetPackTheme>
To change the theme at runtime, you can simply do
myTheme.ThemeUri = new Uri("Path/To/The/Theme.xaml", UriKind.RelativeOrAbsoluteOrWhatever);

Categories

Resources