Xamarin.Forms MergedDictionaries - c#

I have created few XAML styles and added them all into App.xaml.cs as MergedDictionaries
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Axon.Mobile.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionaries/Colors.xaml"/>
<ResourceDictionary Source="ResourceDictionaries/GlobalStylesDictionary.xaml"/>
<ResourceDictionary Source="ResourceDictionaries/KeyStylesDictionary.xaml"/>
<ResourceDictionary Source="ResourceDictionaries/ReceptionStylesDictionary.xaml"/>
<ResourceDictionary Source="ResourceDictionaries/PutAwayStylesDictionary.xaml"/>
<ResourceDictionary Source="ResourceDictionaries/ViewModelLocatorDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
This soolution is working when I use style defined in any dictionary as StatisResouce i.e:
<Label TextColor="{StaticResource Test1}"/>
However I would like to create dynamic resources and in that case I need to replace the styles in C#. The problem is that
Application.Current.Resources
contains these 6 another dictionaries as MergedDictionary property. All of given dictionaries are empty.
Why can't I get the defined styles in C#?

That's strange but I've noticed that we can only access resources located in MergedDictionaries using the TryGetValue method for the moment:
if (Application.Current.Resources.TryGetValue("StyleResourceKey", out var objectStyle))
{
var style = (Style)objectStyle;
//Edit your style
}

Related

Cannot remove merged dictionaries from code

I have these dictionaries:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Languages/English.xaml"/>
<ResourceDictionary Source="Resources/Themes/All.xaml"/>
<ResourceDictionary Source="Resources/Themes/Green.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
I want to remove the dictionaries in C#. Tried these but failed:
this.Resources.MergedDictionaries.Clear();
this.Resources.MergedDictionaries.Remove(this.Resources.MergedDictionaries[0]);
I get this error when I use .Clear() method.
I was able to clear the merged dictionary using this line:
this.Resources.MergedDictionaries[0].Clear();
I then added the wanted dictionary with this line:
this.Resources.MergedDictionaries.Add(languageResourceDictionary);

XAML Designer error: "IOException: Cannot locate resource" - How to provide a Pack URI that works with dynamic assembly name?

We have a ResourceDictionary being referenced as follows
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Theming/AppTheme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
This works great at runtime. However, the Designer in Visual Studio gives an error in views that reference this UserControl:
IOException: Cannot locate resource 'theming/apptheme.xaml'.
Other SO answers have suggested referencing the ResourceDictionary by specifying the assembly name:
<ResourceDictionary Source="pack://application:,,,/MyDomain.MyApp.Wpf;component/Theming/AppTheme.xaml" />
This makes the Designer happy, but our assembly name is different in staging vs. production, so it would be nice if we didn't have to specify the assembly name. My question is: How can we provide a ResourceDictionary Source URI that makes the Designer happy and does not require specifying the assembly name?
If this is not possible, we might make the URI a static value that is different per build configuration using preprocessor directives.
You can define the UI or resources for your app using XAML.
Resources are typically definitions of some object that you expect to use more than once. To refer to a XAML resource later, you specify a key for a resource that acts like its name.
You can reference a resource throughout an app or from any XAML page within it.
You can define your resources using a ResourceDictionary element from the Windows Runtime XAML.
Then, you can reference your resources by using a StaticResource markup extension or ThemeResource markup extension.
Resources don't have to be strings.
they can be any shareable object, such as styles, templates, brushes, and colors. However, controls, shapes, and other FrameworkElements are not shareable, so they can't be declared as reusable resources.
Example:
<Page.Resources>
<x:String x:Key="key1">Hey</x:String>
<x:String x:Key="key2">Nice</x:String>
</Page.Resources>
you can use those resoures by addressing the keys in their proper location i.e.:
<Label Text="{StaticResource key1}" FontSize="Large" VerticalAlignment="Center"/>
Well, In order to make your project more organized you need to make a ResourceDictionary a seperate file and call it like this (ContentPage part is depending on the page):
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ContentPage.Resources>
// in this example Styles is in the same folder has the page you can make dynamic resource to access it from all areas or make a path in a proper manner like:
xmlns:themes = "clr-namespace:AppName.Themes;assembly=AppName"
How can we provide a ResourceDictionary Source URI that makes the Designer happy and does not require specifying the assembly name?
you make a dynamic one.
like this:
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
x:Class="App.Themes.Theme"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Color x:Key="PrimaryColor">#ffffff</Color>
<Color x:Key="PrimaryDarkColor">#0f0f0f</Color>
</ResourceDictionary>
and in app.xaml you do this (if Theme is in folder Themes in main project):
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:themes = "clr-namespace:YourProjectName.Themes;assembly=YourProjectName"
x:Class="YourProjectName.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<themes:Theme />
</ResourceDictionary.MergedDictionaries >
</ResourceDictionary>
</Application.Resources>
then you can do stuff like this anywhere:
BackgroundColor="{DynamicResource PrimaryColor}"
Good Luck!

Nesting ResourceDictionaries with MergedDictionaries in UWP

I'm trying to split up a ResourceDictionary containing styles for multiple controls in our current UWP application. The file has grown to about 3000 lines and has become a living hell to manage, so I decided to split it up into smaller, more specific ResourceDictionaries and include them using MergedDictionaries.
App.xaml
<common:BootStrapper x:Class="Asteria.Ion.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="using:Template10.Common"
xmlns:styles="using:Asteria.Ion.Styles"
RequestedTheme="Dark">
<common:BootStrapper.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles\Custom.xaml" />
<ResourceDictionary Source="Styles\CustomControls.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</common:BootStrapper.Resources>
</common:BootStrapper>
CustomControls.xaml contains references to other ResourceDictionaries.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Template10.Controls"
xmlns:behaviors="using:Template10.Behaviors"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:Asteria.Ion.Styles">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Shared.xaml" />
<ResourceDictionary Source="Templates.xaml" />
<ResourceDictionary Source="ComponentBlock.xaml" />
<ResourceDictionary Source="FlowAgent.xaml" />
<ResourceDictionary Source="Planning.xaml" />
<ResourceDictionary Source="ProjectDialog.xaml" />
<ResourceDictionary Source="Inspector.xaml" /-->
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
This will always produce the following exception:
Failed to assign to property 'Windows.UI.Xaml.ResourceDictionary.Source' because the type 'Windows.Foundation.String' cannot be assigned to the type 'Windows.Foundation.Uri'. [Line: 12 Position: 37]
I've tried changing the source URI numerous times, but it keeps giving this error. Only commenting out all the ResourceDictionary elements in CustomControls.xaml helps. But then I get exceptions concerning missing styles of course.
Some URI formats I've tried:
/Styles/Shared.xaml
Styles/Shared.xaml
Styles\Shared.xaml
.\Shared.xaml
ms-appx:///Styles/Shared.xaml
None of them work.
Any advice would be appreciated.
In the end it had nothing to do with the URI structure, but with a combination of ThemeDictionaries and MergedDictionaries.
What was working before:
In App.Resources:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/Themes.xaml" />
<ResourceDictionary Source="Styles/CustomControls.xaml" />
</ResourceDictionary.MergedDictionaries>
Where Themes.xaml contained ThemeDictionaries and CustomControls.xaml contained <Styles> ( a lot of them ).
After splitting CustomControls.xaml, it no longer contained any styles, but only MergedDictionaries.
Looking something like this:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ControlStyles/ProjectDialog.xaml" />
<ResourceDictionary Source="ControlStyles/Inspector.xaml" />
</ResourceDictionary.MergedDictionaries>
Inspector.xaml contained a Style using {ThemeResource} and it appears that's where it went wrong. The solution/work-around in the end was to include a MergedDictionaries with a references to Themes.xaml in Inspector.xaml.
Now if anyone can explain the exact reasoning behind this solution, I'd be much obliged.
From the error message,XAML Compiler failed to translate the Source Property of nested ResourceDictionaries. The easiest and fastest workaround is to add the nested ResourceDictionaries in App.Xaml.cs:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
...
var applicationMergedDics = Application.Current.Resources.MergedDictionaries;
applicationMergedDics[0].MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("ms-appx:///Styles/Shared.xaml") });
applicationMergedDics[0].MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("ms-appx:///Styles/Templates.xaml") });
...
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
Notes: Don't forget to remove the MergedDictionaries in CustomControls.xaml. And the error will be gone.

WPF Cannot locate resource

I have a resource file and two views. This views use a resource file
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
And it will work while i dont put one view to the another. In this case i get this error
Cannot locate resource 'dictionary1.xaml'
How to fix it?
Use Pack Uri's
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Assembly_Name;component/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
If Dictionary1.xaml in your project's rootpath, remove '/' before Dictionary1
<ResourceDictionary Source="Dictionary1.xaml"/>
Or you can use packuri like :
/yourAssemblyName;component/Dictionary1.xaml

How to apply styles to all windows in WPF app?

I have the following App.xaml file:
<Application x:Class="MiniDeviceConfig.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MiniDeviceConfig.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Button.xaml"/>
<ResourceDictionary Source="CheckBox.xaml"/>
<ResourceDictionary Source="ComboBox.xaml"/>
<ResourceDictionary Source="Common.xaml"/>
<ResourceDictionary Source="GroupBox.xaml"/>
<ResourceDictionary Source="Label.xaml"/>
<ResourceDictionary Source="LinkButton.xaml"/>
<ResourceDictionary Source="ListBox.xaml"/>
<ResourceDictionary Source="ListView.xaml"/>
<ResourceDictionary Source="RadioButton.xaml"/>
<ResourceDictionary Source="Tooltip.xaml"/>
<ResourceDictionary Source="Window.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
In my application, my main window is MiniDeviceConfig.xaml (as seen above). In my Button.xaml file, I clearly set the button height to some obscene number. And, this size is reflected in my main window's buttons. However, some action on the main window triggers a modal window that has more buttons on it. I was expecting the same tall buttons but no such luck. How do I get the style to propagate into all windows in the application?
You can try very helpful class ThemeManager from http://wpfthemes.codeplex.com. In our project we had similiar problems and solve it by using it.
Figured it out. There were other resources included that were conflicting.

Categories