I have a folder in my project, Templates, full of (compiled) XAML ResourceDictionaries.
In a UserControl, I want to load all the templates into the ResourceDictionary. I would use code like the following:
public MyView()
{
InitializeComponent();
foreach (var resourceUri in new GetResourceUrisFromTemplatesFolder())
Resources.MergedDictionaries.Add(
new ResourceDictionary
{ Source = new Uri(resourceUri, UriKind.Relative) });
}
What I need to write is the GetResourceUrisFromTemplatesFolder method. I need it to discover all the resources from that folder.
The URIs could take a form like /MyAssembly;component/MyNS/Templates/Template12345.xaml or ../../Templates/Template12345.xaml
Is this possible?
Do I have to manually convert the names from the assembly's compiled resources (MyAssembly.g.resources)?
BTW, one can also manually load a ResourceDictionary as it seems:
ResourceDictionary dict = new ResourceDictionary();
System.Windows.Application.LoadComponent(dict,
new System.Uri("/SomeAssembly;component/SomeResourceDictionary.xaml",
System.UriKind.Relative));
After that, can talk to that dict object using foreach on the Keys property it has etc
At http://msdn.microsoft.com/en-us/library/ms596995(v=vs.95).aspx says
The XAML file that is loaded can be either an application definition file (App.xaml, for example) >or a page file (MainPage.xaml, for example). The XAML file can be in one of the following locations:
Included in the application package.
Embedded in the application assembly.
Embedded within a library assembly at the site of origin.
Do I have to manually convert the names from the assembly's compiled resources (MyAssembly.g.resources)?
That might be the case and i myself would approach it that way, however the question about how to do just that has been answered already so it should be not that much of an issue. Make sure that the dictionaries' compile action matches, and you probably want to prefix the names with a pack uri.
Related
I have a ContentControl/TemplatedControl written in Avalonia Class Library, and the styles defined in a file.
To load the styles, in WPF, you'd need to add AssemblyInfo.cs with this hack
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
Now with Avalonia... what's the way to do it?
EDIT: Is the answer that the client must register the files manually in App.xaml?
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Default.xaml"/>
</Application.Styles>
but then -- what if I want to display multiple such controls with different styles? I could have a property on the control to choose the theme or the colors.
The styles defined in the App.xaml are global, so all controls will be using them. However, it is possible to change them at runtime. In your case you could start with creating a styles dictionary to simplify things and add all those StyleInclude there, so your Application.Styles have only one entry:
<Application.Styles>
<StyleInclude Source="avares://YourAssembly/Path/YourStyles1.xaml"/>
</Application.Styles>
Now, let's say you want to change this resource to YourStyles2.xaml in the code.
private static StyleInclude CreateStyle(string url)
{
var self = new Uri("resm:Styles?assembly=YourAssembly");
return new StyleInclude(self)
{
Source = new Uri(url)
};
}
private void SetStyles()
{
var newStyles = CreateStyle("avares://YourAssembly/Path/YourStyles2.xaml");
Avalonia.Application.Current.Styles[0] = newStyles;
}
In Resources.resx, when accessing a resource in C# visual studio, you do it by : "Properties.Resources." and then a list of resources is avaulable for selection.
I am trying to access resources without knowing the resource name in advanced, its name is revealed on run time only from a content of some string.
Is there any direct way to access the Resources.resx resources names or it can only be done by collecting all resources to a dictionary or some thing like that?
Yes, you can load the resource string manually using code similar to the below:
Assembly resourceAssembly = Assembly.Load("<AppName>.Resources");
ResourceManager resourceManager = new ResourceManager("<AppName>.Resources.<ResourceName>", resourceAssembly);
string resource = resourceManager.GetString("<ResourceName>", culture));
My main Windows Forms (managed C++) project has a class that presents an image with tiles that can be shown or hidden to create a responsive diagram.
I created a separate utility app that helps me get all the images positioned correctly, etc. This app is written in C# and writes a .resx file containing the image data and positioning, using the following code snippet:
using(ResXResourceWriter resx = new ResXResourceWriter(sfd.FileName)) {
resx.AddResource("Size", canvas.Size);
List<int> IDs = canvas.IDs;
resx.AddResource("IDList", IDs);
resx.AddResource("BackgroundIndex", canvas.BackgroundIndex);
foreach(int id in IDs) {
String positionKey = String.Format("Position.id{0}", id);
String visibilityKey = String.Format("Visibility.id{0}", id);
String imageKey = String.Format("Image.id{0}", id);
resx.AddResource(imageKey, canvas.TileImage(id));
resx.AddResource(positionKey, canvas.TilePosition(id));
resx.AddResource(visibilityKey, canvas.TileVisible(id));
}
}
I can open the .resx file in a text editor and see that it is well-formed and contains the expected data.
Then I take that .resx file and add it to my main application's project. Now I can't figure out how to get at the resources inside it. The code I've tried is:
ResourceManager ^ image_rm = gcnew ResourceManager(
"resx_file_name_without_extension", GetType()->Assembly);
ResourceSet ^ image_rs = image_rm->GetResourceSet(
System::Globalization::CultureInfo::CurrentCulture, true, true);
At runtime, the second line (the GetResourceSet call) throws a System.Resources.MissingManifestResourceException with the following message text:
Resource load failure:
Could not find any resources appropriate for the specified culture or the
neutral culture. Make sure "resx_file_name_without_extension.resources" was
correctly embedded or linked into assembly "my_assembly" at compile time, or
that all the satellite assemblies required are loadable and fully signed.
I suspect my problem is...well I don't really know. Maybe I'm not using the right identifier in the ResourceManager constructor. I tried explicitly setting "Excluded From Build: No" and "Content: Yes" in the file's properties, but that had no effect.
Is it even possible to drop an externally-created .resx file into a project and get at the resources within? I definitely need it compiled in; I can't ship a product with dangling .resx files. I can always create a set of static data objects in .cpp files, but the .resx approach seemed more elegant...
Turns out a comment on this unanswered question was the secret sauce. Prepending the root namespace to the identifier made the ResourceManager happy:
ResourceManager ^ image_rm = gcnew ResourceManager(
"my_root_namespace.resx_file_name_without_extension", GetType()->Assembly);
ResourceSet ^ image_rs = image_rm->GetResourceSet(
System::Globalization::CultureInfo::CurrentCulture, true, true);
Just how or why the compiler decided to place the resources within that namespace is still a bit of a mystery to me, but that's trivia for another day.
The question to which I link involves a .resx created with VS within the project, and mine involves adding one created externally, so I think it's a different-enough situation to warrant a separate Q/A.
Class Library A
Strings
en-US
Resources.resw
zh-CN
Resources.resw
Application
Views
ViewA.xaml
So I have a View, ViewA that I need to manually load localized strings from. However, whenever I do this, I receive an empty string.
I have tried:
var loader = ResourceLoader.GetForCurrentView();
var myLocalizedText = loader.GetString("Foo");
and
var loader = new ResourceLoader();
var myLocalizedText = loader.GetString("Foo");
The variable myLocalizedText is always an empty string.
I tried to reproduce your issue, however I just got ResourceMap Not Found. exception when using ResourceLoader.GetForCurrentView() or new ResourceLoader().
If we want to construct a resource loader for resources from a library package, we need use ResourceLoader.GetForCurrentView(String) method or ResourceLoader.ResourceLoader(String) constructor. Here the String is the resource identifier of the ResourceMap that the new resource loader uses for unqualified resource references.
Components or library files are typically added into a subfolder of the package they are included in during the build process, similar to their string resources. Their resource identifier usually takes the following form:
ClassLibraryOrAssemblyName/ResourceFileName/StringName
So for your case, we can use following code to load localized strings:
var loader = ResourceLoader.GetForCurrentView("ClassLibraryA/Resources");
var myLocalizedText = loader.GetString("Foo");
For more information, please see: Loading strings from libraries or controls and scenario 6 in Application resources and localization sample.
Besides, please note that for a UWP app, it's better to use GetForCurrentView(String) method:
[ResourceLoader(String) may be altered or unavailable for releases after Windows 8.1. Instead, use GetForCurrentView(String).]
Also if you want to add Chinese language, you'd better use zh-Hans instead of zh-CN:
Include script when there is no suppress script value defined for the language. See the IANA subtag registry for language tag details. For example, use zh-Hant, zh-Hant-TW, or zh-Hans, and not zh-CN or zh-TW.
For more information see: Qualify resources with their language.
I'm trying to load a ResourceDictionary object into code so that I can check if it contains a certain value before trying to bind to it, but for some reason it can't find the resource. It might be something basic, ie having the wrong build action or URI but can someone point me in the right direction?
The .cs file and the Images.xaml resource dictionary are both in the same folder and namespace
This is the code that is failing
ResourceDictionary resourceDictionary = new ResourceDictionary();
resourceDictionary.Source = new Uri("Images.xaml", UriKind.Relative);
Any idea what I'm doing wrong? getting error message
{"Cannot locate resource 'images.xaml'."}
The XAML parser probably adds an application authority when converting URIs, in code you may need to add that yourself. Build action should just be the default for ResourceDictionaries, whatever that may be.