I have a .NET 4.0 WPF application where the user can change the language (culture) I simply let the user select a language, create a corresponding CultureInfo and set:
I'm going to chime in here.
I successfully did this using the OverrideMetadata()
method that the OP mentioned:
var lang = System.Windows.Markup.XmlLanguage.GetLanguage(MyCultureInfo.IetfLanguageTag);
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(lang)
);
But, I still found instances in my WPF in which the system culture was being applied for dates and number values. It turned out these were values in <Run>
elements. It was happening because the System.Windows.Documents.Run
class does not inherit from System.Windows.FrameworkElement
, and so the overriding of metadata on FrameworkElement
obviously had no effect.
System.Windows.Documents.Run
inherits its Language
property from System.Windows.FrameworkContentElement
instead.
And so the obvious solution was to override the metadata on FrameworkContentElement
in the same way. Alas, doing do threw an exception (PropertyMetadata is already registered for type System.Windows.FrameworkContentElement), and so I had to do it on the next descendant ancestor of Run
instead, System.Windows.Documents.TextElement
:
FrameworkContentElement.LanguageProperty.OverrideMetadata(
typeof(System.Windows.Documents.TextElement),
new FrameworkPropertyMetadata(lang)
);
And that sorted out all my issues.
There are a few more sub-classes of FrameworkContentElement
(listed here) which for completeness should have their metadata overridden as well.
It's not completely your answer, but I used this to reload the resources. But you still need to reload the windows...
List<Uri> dictionaryList = new List<Uri>();
foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries)
{
dictionaryList.Add(dictionary.Source);
}
Application.Current.Resources.MergedDictionaries.Clear();
foreach (Uri uri in dictionaryList)
{
ResourceDictionary resourceDictionary1 = new ResourceDictionary();
resourceDictionary1.Source = uri;
Application.Current.Resources.MergedDictionaries.Add(resourceDictionary1);
}
I'm not sure how to get around the "can't call OverrideMetadata multiple times" exception.
As a workaround, when the user changes UI cultures in your app, you could restart your app with that culture, passing in the new culture as a command line argument. Unless your users will be changing cultures often, this sounds like a reasonable solution.
I never found a way to do exactly what I asked for in the question. In my case I ended up solving it by having all my usercontrols inherit from a superclass that contained this:
/// <summary>
/// Contains shared logic for all XAML-based Views in the application.
/// Views that extend this type will have localization built-in.
/// </summary>
public abstract class ViewUserControl : UserControl
{
/// <summary>
/// Initializes a new instance of the ViewUserControl class.
/// </summary>
protected ViewUserControl()
{
// This is very important! We make sure that all views that inherit
// from this type will have localization built-in.
// Notice that the following line must run before InitializeComponent() on
// the view. Since the supertype's constructor is executed before the type's
// own constructor (which call InitializeComponent()) this is as it
// should be for classes extending this
this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);
}
}
When the user changes the language I then create new instances of any usercontrols that are currently running.
This solved my problem. However, I would still like a way to do this "automatically" (i.e. without having to keep track of any instantiated objects).
Just my two cents: After almost going crazy when trying to implement ComponentOne WPF controls (DataGrid and C1DatePicker) with my German language assembly I stumbled upon this page.
This seems to be directing in the right way: I just entered the above code into my App.xaml.cs / Application_startup routine and now German date/time formatting for C1DatePicker finally works.
Got to test DataGrid right after that.
private void Application_Startup(object sender, StartupEventArgs e)
{
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag)));
}
Thanks!
Update: Tested C1DataGrid for WPF - works! This solved all the problems I had with international Date / Time settings in my Applications. Great!
I pretty much had the same issue.
I found this: http://www.codeproject.com/Articles/35159/WPF-Localization-Using-RESX-Files (might not be the original source).
It discusses a markup extension named "UICultureExtension" which is attached to the Language property of all framework elements that need localization (in XAML).
If you raise a UI language changed event, static extension managers in the background will update all registered framework elements.