How to access resource located in merged dictionary from code - xaml

I have a bunch of Colors inside a couple of ResourceDicitonaries like this:
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:s="clr-namespace:System;assembly=netstandard">
<Color x:Key="Color.Background">#301536</Color>
</ResourceDictionary>
And I simply add both to the App.xaml like so:
<!--Colors-->
<ResourceDictionary Source="Resources/Colors/Light.xaml"/>
<ResourceDictionary Source="Resources/Colors/Dark.xaml"/>
The ResourceDicitonary file is simply a .xaml file without any bundled .cs, and both of the two dictionaries are set on the App.xaml without having to define them inside a MergedDicionaries group.
When trying to access the a Color from the code, I'm not able to find it, looks like it was not added to the resource list.
var color = Application.Current.Resources.FirstOrDefault(f => f.Key == "Color.Background")
.Value as Color? ?? Color.Crimson;
Is there any way to access a resource like FindResource/TryFindResource available in WPF?
I also tried to access/see the contents of the MergedDictionaries but for some reason the merged dictionaries are always empty.

Thanks to another person I was able to construct this working code:
internal static Color TryGetColor(string key, Color fallback)
{
Application.Current.Resources.TryGetValue(key, out var color);
return color as Color? ?? fallback;
}

According to your description, you want to add multiple ResourceDictionary in APP.xaml, it doesn't work.
I find one article about this issue, you can take a look:
https://nicksnettravels.builttoroam.com/post/2018/09/02/Getting-Started-with-XamarinForms-and-Resource-Dictionaries.aspx

Related

Xamarin.Forms correct way of Binding in ResourceDictionary Controls

I'm having problems getting this to work.
<ResourceDictionary>
<ViewCell x:Key="Separator">
<Label Text="{Binding Title}" />
</ViewCell>
</ResourceDictionary>
The class Option contains a property named Title which is set to whatever text. However the following code is not working. No text appears in the label. Text just stays "null". What am I doing wrong - how can I set the Binding correctly?
if (Resources.ContainsKey("Separator"))
{
var cell = Resources["Separator"] as Cell;
if (cell != null)
{
cell.BindingContext = option;
section.Add(cell);
}
}
Objects in a ResourceDictionary are created only once, and their instances are shared everytime you use them. As ViewCell and Binding can not be reused, this is unlikely to work.
What you can define in the ResourceDictionary is a DataTemplate containing the ViewCell, and in that case, it can be shared as the DataTemplate content will be recreated for each usage.

Runtime change Resource Dictionary for a Windows 8.1 XAML Store App

I am trying to dynamically change my resource dictionary definitions for my application during run time.
I am doing this because I would like to have different font sizes, scaling etc for my application based on the view port size.
I currently have the following code which gets executed every time the view port size changes:
string stylesPath;
if (args.Type == "small")
{
stylesPath = "ms-appx:///Styles/small.xaml";
}
else
{
stylesPath = "ms-appx:///Styles/standard.xaml";
}
var resourceDictionary = new ResourceDictionary
{
Source = new Uri(stylesPath, UriKind.RelativeOrAbsolute)
};
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);
This works for the initial load. When I change my view port this code does get hit again, but after the resources dictionaries are cleared and reloaded my application's fonts/styles/etc don't change at all.
It appears that the application styles will only be loaded once during application start up.
Does anyone know of a way I can force my application to redraw itself based on the new resource dictionary values?
This can be accomplished using Themes. There is a handy nuget package, called Theme Manager, that makes it very easy to switch themes.
Instead of loading your themes on app load, put them in your app ThemeDictionaries
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Themes/small.xaml"/>
<ResourceDictionary Source="/Themes/standard.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
Then you can change the theme like such:
var url = new Uri(string.Format("ms-appx:///Themes/{0}.xaml", (args.Type == "small") ? "small" : "standard"));
ThemeManager.ChangeTheme(url);
You can read more about ThemeManager here.

how to change selected item background based on page

I want to change selected item background color of my GridView based on pages. I define a Color property in each ViewModels, then assign the ViewModel to the view's DataContext. I edit the ItemContainerStyle in app.xaml and want to bind the ViewModel's color property to the selectionbackground, so that the background color of selected item is different in each views, but it doesn't work, I couldn't see the expected color. Anyone can help?
If we apply styles in the app.xaml page they will apply to all our application.
I think you can do this by defining your resources at page level using "UserControl.Resources" in your page.
<UserControl.Resources>
<Style TargetType="...">
...
</Style>
</UserControl.Resources>
You can even set key property in the style and apply to the control like bellow
<UserControl.Resources>
<Style x:Key="my_key" TargetType="...">
....
</Style>
</UserControl.Resources>

How to Assign a XAML Stype from Common/StandardStyles.xaml in code behind

I have search and tried a number of things to do this. I have a style that is successfully bound to multiple XAML frames by doing XAML code like this, the name of the style is ViewPersonTextboxDataStyle:
<TextBox Grid.Row="5" Grid.Column="1" Name="textboxName" Text="{Binding textboxName}" Margin="5,5,5,5" Style="{StaticResource ViewPersonTextboxDataStyle}"/>
So, when I get to another frame where I want to create the Grid rows and definitions in a code behind, I tried this, which I thought was correct:
var resourceDictionary = new ResourceDictionary()
{
Source = new Uri("ms-appx:///Common/StandardStyles.xaml", UriKind.Absolute)
};
var style = resourceDictionary["ViewPersonTextboxDataStyle"] as Style;
textBlock.Style = resourceDictionary["ViewPersonTextboxDataStyle"] as Style;
So at this point, I can see the style was found in the resource dictionary as style is populated correctly. But assigning into textBlock.Style causes a Catastrophic Exception. So, either I am missing a step or this is incorrect.
Not alot of net information on this.
Ok, thank you Raghavendra, this did point me in the right direction to tell me that things I was trying weren't off base.
What I ended up with is:
style = Application.Current.Resources["ViewPersonTextDataStyle"] as Style;
textBlock.Style = style;
Raghavendra is right, you don't need to use resource manager, and you also don't need to define it in the local XAML. I used the above line to do it by assigning current in every one of my frames anyway.
So with that, my exception was one for an IDIOT (namely me). I should have been using my TEXTBLOCK style not my TEXTBOX style. Assigning a textbox style to the textblock was causing the exception.
Try this:
textBlock.style = this.Resources["ViewPersonTextboxDataStyle"] as Style;
You need not use ResourceDictionary
Edit:
this.Resources refers to Page.Resources (that is in case the ViewPersonTextboxDataStyle is defined in Page.Resources we use this)
Try this one:
textBlock.style = App.Current.Resources["ViewPersonTextboxDataStyle"] as Style;

Bind xaml vector images dynamically

I'm looking for a way to bind xaml images dynamically in code.
There are lots of examples online to show how to bind png or xaml images in the window's xaml, or to load png files in code.
But I have found no examples for xaml files with build action=page. XmlReader can't handle them since they are compiled to baml.
LoadComponent(new Uri("...filename.baml") will apparently load the baml but what kind of image class do I load this into? BitmapImage(new Uri("...filename.baml") does not seem to work, probably because it's not a bitmap.
Thanks in advance.
Additionally, if your image is stored in a Xaml vector file in this kind of format:
You can load the individual xaml vector images in the following way (it is probably best to prevent the dictionary being added multiple times, if like me, you are loading it via an OpenFileDialog):
C#:
string fullPathAndFileName = "C:\Image_Name.xaml";
ResourceDictionary dict = new ResourceDictionary();
dict.Source = new Uri(fullPathAndFileName);
Application.Current.Resources.MergedDictionaries.Add(dict);
DrawingImage image = dict[dict.Keys.Cast().ToList()[0]] as DrawingImage;
myImage.Source = image;
Xml:
Image Height="200" Width="200" x:Name="myImage"
After much trial and error and searching, the following article helped me on my way:
Access ResourceDictionary items programmatically
If each Xaml vector image is contained inside a ResourceDictionary with a key (see my 2nd post below for the format)...
If your Xaml vector image files are all stored in your project (build action: page), you can load them in the following way:
//Get the ResourceDictionary using the xaml filename:
ResourceDictionary dict = System.Windows.Application.LoadComponent(new Uri("/yourprojectname;component/youriconfolder/youriconfilename.xaml", System.UriKind.Relative)) as ResourceDictionary;
//Get the xaml as a DrawingImage out the ResourceDictionary
DrawingImage image = dict[dict.Keys.Cast<object>().ToList()[0]] as DrawingImage;
I could return the image and bind it to the viewmodel property, which returns the iconfilename.xaml. Then I use a converter with the above code to lookup the icon and return it as a DrawingImage.
Or you can assign it as the source of an Image (see my 2nd post below).
UPDATE: 2015.10.08 - It seems Carl didn't get around to the "XAML format example" part of his post. The XAML would look something like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DrawingImage x:Key="SomeUniqueKey">
<DrawingImage.Drawing>
<DrawingGroup>
...
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</ResourceDictionary>
Then you could do:
DrawingImage image = dict["SomeUniqueKey"] as DrawingImage;
Or, if you prefer using the Image directly,
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Image x:Key="SomeUniqueImage">
<Image.Source>
<DrawingImage>
...
</DrawingImage>
</Image.Source>
</Image>
</ResourceDictionary>
And:
Image someImage = dict["SomeUniqueImage"] as Image;