How to change resources dynamically - c#

I have a window based application in C#. I am trying to do this for some another language, say arabic.
As we know there is resource file for each form. I have created a global resource file as ResouceFileName.ar-SA.resx . Now I want to change all labels dynamically when I change CultureInfo. If i write in designer file like
static class clsLocalization
{
static ResourceManager resManager = new ResourceManager(typeof(Secure_Browser_CS_Version.Properties.Resources));
public static void applyGlobalResources(Control control,string resource)
{
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ar-SA");
control.Text=resManager.GetString(resource);
}
}
// Resource file
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SBMainForm));//Default
//
// settingHdrLbl
//
resources.ApplyResources(this.settingHdrLbl, "settingHdrLbl");
clsLocalization.applyGlobalResources(this.settingHdrLbl, "settingHdrLbl");
this.settingHdrLbl.BackColor = System.Drawing.Color.Transparent;
this.settingHdrLbl.Name = "settingHdrLbl";
This will be reload as default whenever i change in designer file. Pl help me out

Related

Refresh all String Resources when Culture Changed

I've written a WPF app in which user can change culture. The Method in app.xaml.cs looks like this :
public void SelectCulture(string culture)
{
// List all our resources
List<ResourceDictionary> dictionaryList = new List<ResourceDictionary>();
foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries)
{
dictionaryList.Add(dictionary);
}
// We want our specific culture
string requestedCulture = string.Format("Resources/StringResources.{0}.xaml", culture);
ResourceDictionary resourceDictionary = dictionaryList.FirstOrDefault(d => d.Source.OriginalString == requestedCulture);
if (resourceDictionary == null)
{
// If not found, we select our default language
//
requestedCulture = "Resources/StringResources.en-ES.xaml";
resourceDictionary = dictionaryList.FirstOrDefault(d => d.Source.OriginalString == requestedCulture);
}
// If we have the requested resource, remove it from the list and place at the end.\
// Then this language will be our string table to use.
if (resourceDictionary != null)
{
Application.Current.Resources.MergedDictionaries.Remove(resourceDictionary);
Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);
}
// Inform the threads of the new culture
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(culture);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
}
This allows to change on runtime every string resources from different resourcedictionnary.
But not every resources: those which are used in xaml via DynamicResource like this :
<GroupBox Header="{DynamicResource RootSettings}" >
are correctly updated.
But those which are used in C# code like in ViewModel like this :
stTestConnection = System.Windows.Application.Current.Resources["Connectionsucceded"].ToString();
do not update.
All string Resources are declared in different resources dictionaries like this :
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<!-- #region Global -->
<system:String x:Key="CriticalErrorTitle">Critical Error</system:String>
<system:String x:Key="ErrorTitle">Error</system:String>
<system:String x:Key="CloseApp">Application will close</system:String>
Any idea why the string resources used in C# are not updating but the ones used in XAML are ?
Ask me if more info needed.
Thanks
I had to do something similar recently with a runtime theme change performing a colour change using Xamarin in c#.
If I remember correctly then in Xaml with DynaminResource they updated automatically. But when in came to the c# code I had to do so manually. This was triggered by a xamarin OnThemeChanged.
If you have access to a similar method during culture change, you could put all your update logic there.

XAML designer can't locate resource

I've custom control in shared project (resource dictionary in shared project).
Everything works fine in run time, xaml designer however throws exception:
Cannot locate resource 'mycontrol.xaml'.
The problem occurs when loading style for control:
public class MyControl: Control
{
public MyControl()
{
Resources = new ResourceDictionary() { Source = new Uri("pack://application:,,,/mycontrol.xaml") };
Style = (Style)Resources["somekey"];
}
}
Why does it works in run-time and doesn't during design time?
I can detect design time, but what to do then?
The WPF designer seems to have problem when loading xaml files from other projects. Could you try to load the xaml file using this annotation:
pack://application:,,,/PROJECTNAMESPACE;component/mycontrol.xaml
I would try
Uri res = new Uri("pack://siteoforigin:,,,/mycontrol.xaml", UriKind.Relative);
Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = res });

Change Language/Resource programmatically w/ WPF

I have a DropDown (using MahApps if that is important) that I'd like to use to switch the language "on the fly" in my program.
Language Class
namespace SAM
{
public class Language
{
public string Title { get; set; }
public string Culture { get; set; }
}
}
Change Language
private void DropLanguage_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
Language lang = DropLanguage.SelectedItem as Language;
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang.Culture);
}
I have all my strings as resources in Resources.resx (default) and Resources.en.resx (english)
3 issues I don't understand
When selecting "englisch" from the dropdown, the language does not change immediately but when I click sth. else, e.g. "close" (it asks "sure?"), the language has changed.
Strings that are directly in the .xaml file like <TextBlock Text="{x:Static p:Resources.Config_HeaderBar_Find_Speaker}" /> do not get updated at all.
Bonus: How would I switch back to the default language, as new CultureInfo(lang.Culture); expects one parameter and for the default I have Culture = null (as the Resources.resx has nothing in it's name). Changing the file to Resources.default.resx messes with my code a lot...
I tried to solve similar problem. The simplest solution for me was to move all Window content to UserControl and creating interface for window with method refreshLanguage(). Then I call from model:
private void SetLanguage(string cultureName)
{
var cul = new System.Globalization.CultureInfo(cultureName);
Properties.Resources.Culture = cul;
System.Globalization.CultureInfo.DefaultThreadCurrentCulture = cul;
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = cul;
System.Threading.Thread.CurrentThread.CurrentUICulture = cul;
System.Threading.Thread.CurrentThread.CurrentCulture = cul;
InitializeHamburgerMenu();
MainWindowView.RegreshLanguage();
RaisePropertyChanged("Title");
}
And RefreshLanguage in Window looks like:
public void RegreshLanguage()
{
GlobalUserControl content = new GlobalUserControl("Views/SettingsPage.xaml");
ContentPresenter_GlobalUserControl.Content = content;
}
In my case, UserControl provides navigation, so I passed last navigated URI as parameter. So, if you need to preserve state you can pass it as parameter to new UserControl. Recreating usercontrol cause all strings to reload without window recreation. Maybe good idea would be to call GC.Collect(); here, but depends on your scenario.
About default neutral culture. For me works to call SetLanguage("").
There are 2 things
Thread.CurrentThread.CurrentCulture
and
Thread.CurrentThread.CurrentUICulture
In order to set these valuse use the static method
CultureInfo.GetCultureInfo(String langCode)
where some examples of the parameter langCode are the following strings
"de-DE"
"en-US"
etc.
more info at
https://msdn.microsoft.com/en-us/library/yck8b540(v=vs.110).aspx
So, overall these lines of code sould work for change in German Language:
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("de-DE");
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");

Windows Store Apps : Loading styles from a customcontrol class library via reflection, OnApplyTemplate is not called?

I am trying to load a custom control library via reflection in windows 8 Metro C# App, the library is loaded but the styles specified in generic.xaml are not loaded, eventually I tried to load the generic.xaml by making it as an Embedded resource and ,then extracted the Generic.xaml to a location and specified the location of it as uri of a ResourceDictionary object, but it throws an error
"Failed to create a 'System.Type' from the text local:CustomControl1"
I cannot create a nuget package or extension SDK as unfortunately that is not my requirement,
Below sample code I wrote to copy the generic.xaml and load it in a resource dictionary
public sealed class CustomControl1 : Control
{
public CustomControl1()
{
this.DefaultStyleKey = typeof(CustomControl1);
Assembly CurrentAssembly = typeof(CustomControl1).GetTypeInfo().Assembly;
var names = CurrentAssembly.GetManifestResourceNames();
var stream = CurrentAssembly.GetManifestResourceStream(names.First());
//generic.xaml is an embedded resource in the current assembly
if (stream != null)
{
//created new generic.xaml here
var file = ApplicationData.Current.LocalFolder.CreateFileAsync("Generic.xaml", CreationCollisionOption.ReplaceExisting).Completed = (o, a) =>
{
var storageFile = o.GetResults();
var s = storageFile.OpenStreamForWriteAsync().Result;
var length = (int)stream.Length;
byte[] bytes = new byte[length];
int output = stream.Read(bytes, 0, length);
s.Write(bytes, 0, length);
s.Flush();
s.Dispose();
var asyncResult = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
var resourceDict = new ResourceDictionary();
var uri = new Uri("ms-appdata:///local/" + storageFile.Name);
resourceDict.Source = uri;
});
};
}
}
// OnApplyTemplate is not called without loading the style from generic.xaml
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
}
The below code I wrote in the custom control library's constructor, so that the control template can be set without generic.xaml
Here since the attribute TargeType="local:CustomControl1" is not present the control gets loaded properly, here since I loaded the style in the constructor, the OnApplyTemplate gets called
StringBuilder sb = new StringBuilder();
sb.Append(#"<ControlTemplate
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
xmlns:d=""http://schemas.microsoft.com/expression/blend/2008""
xmlns:mc=""http://schemas.openxmlformats.org/markup-compatibility/2006"">");
sb.Append(#"<Border Background=""{TemplateBinding
Background}""
BorderBrush=""{TemplateBinding BorderBrush}""
BorderThickness=""{TemplateBinding BorderThickness}"">
<Grid>
<Button x:Name=""Tbx1"" Content=""Hello World"" Foreground=""HotPink""
HorizontalAlignment=""Stretch"" VerticalAlignment=""Stretch""/>
</Grid>
</Border>");
sb.Append(#"</ControlTemplate>");
this.Template = (ControlTemplate)XamlReader.Load(sb.ToString());
but the problem is loading all the styles using XamlReader is not a good idea, unless we are out of Options. As there may be various dependent styles which too have to be loaded.
Check out how they do it in the WinRTXamlToolkit. They create the Generic.xaml for the project and include all control templates inside of separate styles in different ResourceDictionarys packaged next to the respective controls.
To put it more simply (for Templated controls, like you are using):
Make two files for each control, MyControl.cs and MyControl.xaml
In MyControl.cs in your MyControl constructor, set the StyleKey to be typeof(MyControl) (like you are doing currently).
Make sure there is a style for your control with TargetType set to the type of your control. Do the same thing for the ControlTemplate that you have as the Template property set in the Style.
In MyControl.xaml, make a ResourceDictionary that stores all of the necessary styles, templates, and resources.
In your Generic.xaml, create a MergedDictionaries tag under the root and create a ResourceDictionary for each control, setting the Source to the full path of MyControl.xaml
Set each of the .xaml files to be build type of Page with CustomTool set to MSBuild:Compile.
Hope this helps and Happy coding!

Multilingual App, NO defined items, C#

I've been developing a c# app. (It runs OK, there's not problem).
But Now, my boss need it work on English, Spanish and other languages.
I saw some tutorials about how to change languages in my app on different web pages (like this, and this)
My problem is:
I don't have defined any item, I mean, I don't have text boxes, labels or buttons. I just have a form:
While my app is running, it reads a .txt file: If there's a "button" line in the .txt, my app will add a button to my form, if there's a "label" line, it will add a new label.
So, I can't use the .resx file as the tutorials said.
It doesn't work.
I donĀ“t know if I'm doing it wrong or it simply doesn't work
Any idea?
I don't know what to do
I read the. txt file (line by line) and I assign the properties like this
public static Label[] LAB = new Label[2560];
public static int indice_LABEL = 0;
if (TipoElemento == "LABEL")
{
LAB[indice_LABEL] = new Label();
LAB[indice_LABEL].Name = asigna.nombreElemento;
LAB[indice_LABEL].Left = Convert.ToInt32(asigna.left);//LEFT
LAB[indice_LABEL].Top = Convert.ToInt32(asigna.top);//TOP
LAB[indice_LABEL].Width = Convert.ToInt32(asigna.width);
LAB[indice_LABEL].Height = Convert.ToInt32(asigna.height);
//and all I need
...
...
Formulario.PanelGE.Controls.Add(Herramientas.LAB[Herramientas.indice_LABEL]);
Herramientas.indice_LABEL++;
}
If you need to stick with this format, the best solution would be to have 1 file with all the control definitions (name, dimensions, position etc) and another with the text to display to the user
Then when you create each control, instead of assigning it a caption you use the ResourceManager, linked to your 'captions' files (1 for each language) to retrieve the correct string to display
For example:
Language Text File
This will be a simple text file, resource.en-US.txt
Inside, you will need to add simple key>value pairs:
label1=Hello world!
To make another language, simply create another file, resource.fr-FR.txt, and add:
label1=Bonjour le monde!
Application Code
// Resource path
private string strResourcesPath= Application.StartupPath + "/Resources";
// String to store current culture which is common in all the forms
// This is the default startup value
private string strCulture= "en-US";
// ResourceManager which retrieves the strings
// from the resource files
private static ResourceManager rm;
// This allows you to access the ResourceManager from any form
public static ResourceManager RM
{
get
{
return rm ;
}
}
private void GlobalizeApp()
{
SetCulture();
SetResource();
SetUIChanges();
}
private void SetCulture()
{
// This will change the current culture
// This way you can update it without restarting your app (eg via combobox)
CultureInfo objCI = new CultureInfo(strCulture);
Thread.CurrentThread.CurrentCulture = objCI;
Thread.CurrentThread.CurrentUICulture = objCI;
}
private void SetResource()
{
// This sets the correct language file to use
rm = ResourceManager.CreateFileBasedResourceManager
("resource", strResourcesPath, null);
}
private void SetUIChanges()
{
// This is where you update all of the captions
// eg:
label1.Text=rm.GetString("label1");
}
Then all you need to do is change the private string strCulture= "en-US" to "fr-FR" (eg in a combo box), and call the GlobalizeApp() method, and the text in label1 will change from Hello world to Bonjour le monde!
Simple (I hope :) )
Check out this link for a great walkthrough

Categories

Resources