2010-03-05 3 views
19

Je voudrais définir la culture pour l'ensemble de mon application. J'ai essayé les éléments suivants:C# BackgroundWorker culture

Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(wantedCulture); 
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(wantedCulture); 
Application.CurrentCulture = CultureInfo.CreateSpecificCulture(wantedCulture); 

Il travaille pour le thread courant, mais plus tard je crée et commence un thread de travail de fond. Lorsque je crée le travailleur, le thread en cours s'exécute avec la culture wantedCulture mais le thread de travail fonctionnera avec la culture de mon ordinateur.

Des idées pour définir la culture pour l'ensemble de l'application?

Répondre

34

REMARQUE: matériel périmé, assurez-vous de lire la mise à jour au bas des changements dans .NET 4.6

Oui, ceci est une commune demande mais ce n'est pas disponible. Windows initialise toujours un thread de système d'exploitation sur le LCID par défaut du système, configuré dans l'applet Options régionales et linguistiques du Panneau de configuration. Vous pouvez remplacer cela aussi longtemps que vous créez vous-même les threads. Mais ce n'est pas pratique pour les threads threads et les threads qui pourraient avoir été créés par un type de code non géré exécutant votre processus, comme un serveur COM.

Le dernier cas est le problème. .NET n'a aucun problème à exécuter du code managé sur les threads créés par du code non managé. Mais il ne peut rien faire sur la façon dont le thread est initialisé. C'est vrai pour CurrentUICulture mais aussi pour des choses plus obscures comme Thread.SetApartmentState(). Ne sous-estimez pas la probabilité qu'un tel thread exécute du code dans votre programme, les serveurs COM écrits par Microsoft sont très générateurs de threads.

Vous devrez passer à travers votre code avec un peigne à dents fines et trouver tout code qui pourrait fonctionner sur un thread que vous n'avez pas créé. Tout gestionnaire d'événement est suspect, comme toute méthode BeginXxx() qui a un callback. BackgroundWorker est certainement le problème mineur.

Ne pas surcharger la culture du fil peut produire très subtile et difficile à diagnostiquer bugz. Un bon exemple serait une SortedList qui touche une chaîne. Lorsqu'il est exécuté avec la mauvaise culture, il échouera au hasard à trouver les éléments qui sont réellement présents dans la liste. Causée par le fait que la liste n'est plus triée dans une autre culture avec des règles de classement différentes.

Si j'ai réussi à vous faire assez peur alors j'ai eu mon message. Cela m'est arrivé, en déboguant un problème avec un très gros programme qui s'est mal comporté sur une machine danoise. Nous n'avions pas de localisation danoise et avons forcé l'interface utilisateur à fonctionner en anglais. Un thread de travail utilisait un arbre rouge-noir avec une chaîne comme clé. Il a échoué au hasard lorsqu'on lui a demandé de traiter avec Åårdvårks. Ça m'a pris une semaine.


Mise à jour: ce problème a été résolu dans .NET 4.5. La classe CultureInfo a maintenant un DefaultThreadCurrentCulture et DefaultThreadCurrentUICulture. Lorsqu'il est défini, il sera utilisé pour initialiser la culture de n'importe quel thread géré au lieu de la culture système Windows par défaut.La manière exacte dont il interagit avec les threads qui ont été démarrés par le code natif et qui entrent dans le code managé n'est pas encore claire pour moi.


Mise à jour: ce problème a une solution plus complète dans .NET 4.6. La culture coule maintenant automatiquement, le comportement idéal. L'article MSDN pour CultureInfo.CurrentCulture() en parle. Les informations fournies sont encore confuses, expérimentalement, il semble également circuler vers un objet Thread et pas seulement un thread Task ou threadpool et DefaultThreadCurrentCulture n'est pas utilisé. Deux pas en avant, un pas en arrière, un test est recommandé.

1

Ma solution était d'avoir une propriété de culture centrale (Application.CurrentCulture est par thread) et de définir la culture de thread en cours au début d'un thread de travail. Un système de travail aide à cela, car vous pouvez alors facilement exécuter du code générique avant et après l'élément de travail, et la classe de système de travail peut maintenir la culture accessible par ses tâches, vous n'avez donc pas besoin de globals.

0

Vous ne pouvez pas faire cela pour chaque thread nouvellement créé. Vous devriez le faire à la main (mais je ne pense pas que la mise en culture pour les threads du pool de threads soit une bonne idée!). Peut-être que votre application devrait dépend de Application.CurrentCulture ou d'autres choses .. mondiale

1

Tout simplement; Ne le faites pas.

N'effectuez aucune mise en forme spécifique à une culture sur un autre thread que le thread principal (Thread.CurrentThread). Obtenir la culture correcte sur d'autres threads - tous les autres threads créés - est juste une douleur et tôt ou tard, vous oublierez de le configurer correctement. Mieux vaut juste éviter la douleur tous ensemble et seulement faire un formatage spécifique à la culture, la conversion, etc, sur le fil que vous êtes sûr d'être sur les paramètres de culture correcte.

0

de Windows toujours un fil initialise OS à la LCID par défaut du système, configuré dans l'applet Options régionales et linguistiques dans le Panneau de configuration .

Malheureusement, je ne suis pas d'accord avec cela et j'ai trouvé le contraire.

Le système a été installé en anglais américain. Je suis allé au panneau de contrôle tout changé en danois et copié à tous les comptes. Redémarré.

Exécutez l'application de la console en danois. Exécuter l'application Web demander le navigateur, il dit danois. Lancer le fil de l'application web et il est lancé comme US pas danois et je ne peux pas comprendre pourquoi.

0

Je sais que le sujet est ancien mais je me suis retrouvé dans un problème de "thread avec OS culture". Je l'ai résolu ainsi: comme BackgroundWorker est dans un UserControl (il serait valide s'il est dans un Formulaire et ainsi de suite ...) Je place un champ dans le UserControl (ou Form) quand il est construit. Dans le gestionnaire d'événements DoWork, j'utilise ce champ dans mes opérations. Voici le code:

/// <summary> 
    /// Culture in which the GUI creates the control. 
    /// </summary> 
    private readonly CultureInfo _currentCulture; 

    /// <summary> 
    ///  Default constructor. 
    /// </summary> 
    public MyControl() 
    { 
     InitializeComponent(); 
     _currentCulture = CultureInfo.CurrentUICulture; 
    } 

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     ExampleClass.DoCultureDependentOperation(_currentCulture); 
    }