<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");
Related
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
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;
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...
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);
In a WPF application I defined default control styles in separate resource dictionaries (e.g. "ButtonStyle.xaml"), and added them as merged dictionaries to a resource dictionary named "ResDictionary.xaml".
If I refer this "ResDictionary.xaml" as merged dictionary in my App.xaml, the default styles are not applied. However, if I refer the "ButtonStyle.xaml", it works correctly.
If I recompile the same code in .NET 3.5 or 3.0, it recognizes and applies the default styles referred in "App.xaml" through "ResDictionary.xaml", but not in .NET 4.0.
At runtime if I check the Application.Current.Resources dictionary, the default styles are there, but they are not applied, only if I specify the Style property explicitly in the Button control.
Are there any solutions to refer a resource dictionary (containig default styles) this way in .NET 4.0?
App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/ResDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
ResDictionary.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Default/ButtonStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
ButtonStyle.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button">
<Setter Property="Background" Value="Yellow"/>
</Style>
</ResourceDictionary>
The best solution is to add a dummy default style in the resource dictionary where you merge all resources together.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Style/Button.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Control" BasedOn="{StaticResource {x:Type Control}}" />
This could be caused by a known bug when there is a single style in application.resources within app.xaml when not using a startupuri.
The fix is to add an additional style like this...
...
<Style x:Key="unused" />
</Application.Resources>
for more details check out this link.... http://bengribaudo.com/blog/2010/08/19/106/bug-single-application-resources-entry-ignored
There is a sort-of fix for this, but I’ve only been able to make it work at the window level (not the application level).
In order to include a WPF 4.0 resource from a separate project, the resource must be added as a resource in the window’s code behind. The statement belongs in the window’s constructor, prior to the InitializeComponent method call:
public ControlsWindow()
{
this.Resources = Application.LoadComponent(new Uri("[WPF 4.0 ResourceProjectName];Component/[Directory and File Name within project]", UriKind.Relative)) as ResourceDictionary;
InitializeComponent();
}
Note: Replace the '[WPF 4.0 ResourceProjectName]' text with your resource's project name. Also, the '[Directory and File Name within project]' needs to be replaced with the relative location of the resource file (like 'Themes/StandardTheme.xaml')
I go into more details about this issue here.