59 votes

Comment définir et modifier la culture dans WPF

J'ai une application WPF .NET 4.0 dans laquelle l'utilisateur peut changer la langue (culture). Je laisse simplement l'utilisateur sélectionner une langue, créer un CultureInfo correspondant et le définir :

Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;

Dans le code C#, cela fonctionne bien. Cependant, dans les contrôles WPF, la culture est toujours en-US. Cela signifie par exemple que les dates seront affichées au format américain au lieu du format correct pour la culture actuelle.

Apparemment, ce n'est pas un bug. Selon MSDN et plusieurs billets de blog et articles sur StackOverflow, le langage WPF ne suit pas automatiquement la culture actuelle. Il est en-US jusqu'à ce que vous fassiez cela :

FrameworkElement.LanguageProperty.OverrideMetadata(
    typeof(FrameworkElement),
    new FrameworkPropertyMetadata(
        XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag)));

Voir par exemple Problèmes de localisation de StringFormat dans wpf .

Je ne comprends pas complètement ce qui se passe ici. Il semble que la propriété Language de tous les éléments du cadre soit définie sur la culture actuelle. Quoi qu'il en soit, cela fonctionne. Je fais cela au démarrage de l'application et maintenant tous les contrôles fonctionnent comme prévu, et par exemple les dates sont formatées en fonction de la culture actuelle.

Mais maintenant le problème : Selon MSDN FrameworkElement.LanguageProperty.OverrideMetadata ne peut être appelé qu'une seule fois. Et en effet, si je l'appelle à nouveau (lorsque l'utilisateur change de langue), une exception sera levée. Je n'ai donc pas vraiment résolu mon problème.

La question : Comment puis-je mettre à jour de manière fiable la culture dans WPF plus d'une fois et à tout moment du cycle de vie de mes applications ?

(J'ai trouvé ceci en faisant des recherches : http://www.nbdtech.com/Blog/archive/2009/03/18/getting-a-wpf-application-to-pick-up-the-correct-regional.aspx et on dirait qu'il a quelque chose qui marche là. Cependant, je n'arrive pas à imaginer comment le faire dans mon application. Il semble que je doive mettre à jour la langue dans toutes les fenêtres et tous les contrôles ouverts et rafraîchir tous les liens existants, etc.)

1 votes

Je n'ai jamais trouvé le moyen de faire ce que je demandais dans la question.

14voto

Ross Points 2138

Je vais intervenir ici.

J'ai réussi à le faire en utilisant le OverrideMetadata() que l'OP a mentionné :

var lang = System.Windows.Markup.XmlLanguage.GetLanguage(MyCultureInfo.IetfLanguageTag);
FrameworkElement.LanguageProperty.OverrideMetadata(
  typeof(FrameworkElement), 
  new FrameworkPropertyMetadata(lang)
);

Mais j'ai encore trouvé des cas dans mon WPF où la culture du système était appliquée pour les dates et les valeurs numériques. Il s'est avéré qu'il s'agissait de valeurs dans <Run> éléments. Cela se produisait parce que le System.Windows.Documents.Run n'hérite pas de la classe System.Windows.FrameworkElement et, par conséquent, le remplacement des métadonnées sur le site FrameworkElement n'a manifestement eu aucun effet.

System.Windows.Documents.Run hérite de son Language propriété de System.Windows.FrameworkContentElement à la place.

Et donc la solution évidente était de remplacer les métadonnées sur FrameworkContentElement de la même manière. Hélas, en le faisant, une exception ( PropertyMetadata est déjà enregistré pour le type System.Windows.FrameworkContentElement ), et j'ai donc dû le faire sur l'ancêtre descendant suivant de Run à la place, System.Windows.Documents.TextElement :

FrameworkContentElement.LanguageProperty.OverrideMetadata(
  typeof(System.Windows.Documents.TextElement), 
  new FrameworkPropertyMetadata(lang)
);

Et ça a réglé tous mes problèmes.

Il existe quelques autres sous-classes de FrameworkContentElement (énuméré aquí ) qui, par souci d'exhaustivité, devraient également voir leurs métadonnées remplacées.

1 votes

Merci, bien que vous ne répondiez pas tout à fait à la question de l'OP, vous avez certainement répondu à la mienne. Je me heurtais à un problème lorsque je le réglais sur FrameworkContentElement ). Vous trouverez le code qui s'occupe des autres sous-classes à l'adresse suivante gist.github.com/adrianratnapala/6775b8de586317812ad5

8voto

huttelihut Points 1621

Je n'ai jamais trouvé le moyen de faire exactement ce que je demandais dans la question. Dans mon cas, j'ai fini par résoudre le problème en faisant en sorte que tous mes usercontrols héritent d'une superclasse qui contient ceci :

/// <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);
    }
}

Lorsque l'utilisateur change de langue, je crée alors de nouvelles instances de tous les usercontrols en cours d'exécution.

Cela a résolu mon problème. Cependant, j'aimerais toujours pouvoir le faire "automatiquement" (c'est-à-dire sans avoir à garder la trace des objets instanciés).

0 votes

Bonjour, j'ai le même problème. J'essaie de changer la langue d'entrée par 'InputLanguageManager.SetInputLanguage(_targetKeyboardWindow, CultureInfo.CreateSpecificCulture("ru"));' et ensuite je recharge ma vue et configure la langue dans le constructeur. Mais CultureInfo.CurrentCulture.IetfLanguageTag . Que dois-je faire, pour changer la langue au moment de l'exécution ?

0 votes

@T.J.Kjaer - votez pour revenir avec une réponse. Tant de gens se défilent devant leur propre question.

6voto

Judah Himango Points 27365

Je ne sais pas comment contourner l'exception "can't call OverrideMetadata multiple times".

Comme solution de rechange, lorsque l'utilisateur change de culture d'interface utilisateur dans votre application, vous pouvez redémarrer votre application avec cette culture, en passant la nouvelle culture comme argument de ligne de commande. À moins que vos utilisateurs ne changent souvent de culture, cela semble être une solution raisonnable.

2 votes

Pour les futurs visiteurs : C'est la solution à l'exception "can't call OverrideMetadata multiple times" : Question sur le SO

5voto

RJ Moeller Points 253

Juste mes deux centimes : Après avoir failli devenir fou en essayant d'implémenter les contrôles WPF de ComponentOne (DataGrid et C1DatePicker) avec mon assemblage en langue allemande, je suis tombé sur cette page.

Cela semble être dirigé dans le bon sens : Je viens d'entrer le code ci-dessus dans ma routine App.xaml.cs / Application_startup et maintenant le formatage allemand de la date/heure pour C1DatePicker fonctionne enfin.

Je dois tester DataGrid juste après ça.

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        FrameworkElement.LanguageProperty.OverrideMetadata(
            typeof(FrameworkElement),
            new FrameworkPropertyMetadata(
            System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag)));
    }

Gracias.

Mise à jour : Testé C1DataGrid pour WPF - fonctionne ! Cela a résolu tous les problèmes que j'avais avec les paramètres internationaux de date/heure dans mes applications. Excellent !

3voto

rbee Points 11

J'ai eu à peu près le même problème.

J'ai trouvé ça : http://www.codeproject.com/Articles/35159/WPF-Localization-Using-RESX-Files (il se peut que ce ne soit pas la source originale).

Il traite d'une extension de balisage nommée "UICultureExtension" qui est attachée à la propriété Language de tous les éléments du cadre qui nécessitent une localisation (dans XAML).

Si vous déclenchez un événement de changement de langue de l'interface utilisateur, les gestionnaires d'extensions statiques en arrière-plan mettront à jour tous les éléments de structure enregistrés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X