Как использовать пользовательские настройки региона и языка Windows в WPF - PullRequest
7 голосов
/ 08 сентября 2011

Я работаю в Намибии. Намибия не является опцией в настройках региона и языка Windows, но делится большинством культурных особенностей с Южной Африкой, поэтому мы выбираем английский язык Южная Африка, а затем настраиваем символ валюты на «N $» (намибийские доллары) а не "R" (южноафриканский рэнд).

Однако я не могу убедить WPF использовать настроенную валюту. Использование string.format("{0:c}", foo) в коде работает нормально, но использование {Binding Path=SomeCurrencyValue, StringFormat=c} `в XAML по-прежнему использует символ« R », а не пользовательский символ« N $ ».

В App.xaml.cs Я установил прикладную культуру со следующим кодом:

System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(System.Globalization.CultureInfo.CurrentCulture.LCID, true);

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

В качестве демонстрации приведем код XAML, который показывает проблему:

<StackPanel>
    <TextBlock>
        Formatted in XAML with: <LineBreak/>
        Text="{Binding Path=SomeCurrencyValue, StringFormat=c}" <LineBreak/>
        Result:
    </TextBlock>

    <TextBox Text="{Binding Path=SomeCurrencyValue, StringFormat=c, Mode=OneWay}"
             Margin="5"/>

    <TextBlock>
        Formatted in code with: <LineBreak/>
        return string.Format("{0:c}", SomeCurrencyValue); <LineBreak/>
        Result:
    </TextBlock>

    <TextBox Text="{Binding Path=SomeCurrencyString, Mode=OneWay}"
             Margin="5"/>

</StackPanel>

DataContext для указанного выше представления содержит следующее:

public double SomeCurrencyValue
{
    get { return 34.95; }

}

public string SomeCurrencyString
{
    get
    {
        return string.Format("{0:c}", SomeCurrencyValue);
    }
}

И результат выглядит так: Currency Issue Result

Я знаю, что есть похожий вопрос здесь , но я надеялся получить лучшие ответы с более полным вопросом. Я в основном работаю над финансовыми приложениями для намибийских клиентов, так что это довольно серьезная проблема для меня - если нет способа сделать это с .NET 4.0, я бы рассмотрел вопрос об отчете об ошибке, но я просто хотел сначала проверить здесь .

EDIT:

Просто открыл награду за этот вопрос. Я надеюсь либо на решение, которое не является нелепым обходным путем, либо на подтверждение того, что это ошибка и ее следует подавать как таковой.

Ответы [ 2 ]

4 голосов
/ 19 сентября 2011

Одним из решений этой проблемы является создание этой Намибийской CultureInfo, поэтому она полностью распознается всеми слоями .NET.Вот код, который делает это:

public static void RegisterNamibianCulture()
{
    // reference the sysglobl.dll assembly for this
    CultureAndRegionInfoBuilder namibianCulture = new CultureAndRegionInfoBuilder("en-NA", CultureAndRegionModifiers.None);

    // inherit from an existing culture
    namibianCulture.LoadDataFromCultureInfo(new CultureInfo("en-za"));
    namibianCulture.CultureEnglishName = "Namibia";
    namibianCulture.RegionEnglishName = "Namibia";
    namibianCulture.CultureNativeName = "Namibia"; // you may want to change this
    namibianCulture.RegionNativeName = "Namibia"; // you may want to change this

    // see http://en.wikipedia.org/wiki/ISO_3166-1, use user-defined codes
    namibianCulture.ThreeLetterISORegionName = "xna"; // I use x as 'extended' and 'na' as namibia
    namibianCulture.TwoLetterISORegionName = "xn";
    namibianCulture.ThreeLetterWindowsRegionName = namibianCulture.ThreeLetterISORegionName;

    // see http://www.currency-iso.org/dl_iso_table_a1.xml
    namibianCulture.ISOCurrencySymbol = "nad";
    namibianCulture.CurrencyEnglishName = "Namibia Dollar";
    namibianCulture.CurrencyNativeName = "Namibia Dollar"; // you may want to change this

    // this is were you build something specific, like this symbol you need
    namibianCulture.NumberFormat.CurrencySymbol = "N$";

    // you'll need admin rights for this
    namibianCulture.Register();
}

public static void UnregisterNamibianCulture()
{
    CultureAndRegionInfoBuilder.Unregister("en-NA");
}

После того, как вы однажды вызвали функцию Register на данном компьютере (вам нужно будет установить эту культуру на компьютерах конечных пользователей), вы теперь можете использовать свой исходный WPFзагрузочный код, просто измените его так:

System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-NA");

И все должно работать как положено.Вы также можете использовать стандартные языковые теги и все такое прочее, так как en-NA теперь распознается.

1 голос
/ 09 января 2013

У меня возникла та же проблема, и я начал с ответа Саймона (спасибо Саймону) о внесении некоторых изменений, чтобы каждый раз при запуске приложения настраивать пользовательскую конфигурацию («Регион и язык» на панели управления), а не настройку по умолчанию.

Мой код выглядит так

public MainWindow()
{
    CreateAndRegisterLocalizedCulture();
    this.Language = XmlLanguage.GetLanguage(customCultureName);

    InitializeComponent();

    DataContext = new ViewModel();
}

private void CreateAndRegisterLocalizedCulture()
{
    CultureAndRegionInfoBuilder customCulture = new CultureAndRegionInfoBuilder(customCultureName, CultureAndRegionModifiers.None);

    // Inherits from the current culture and region, may be configured by the user
    customCulture.LoadDataFromCultureInfo(CultureInfo.CurrentCulture);
    customCulture.LoadDataFromRegionInfo(RegionInfo.CurrentRegion);

    // Not needed for the culture sake but... 
    customCulture.CultureEnglishName = CultureInfo.CurrentCulture.EnglishName + "-Customized";
    customCulture.CultureNativeName = CultureInfo.CurrentCulture.NativeName + "-Customized";

    // If the custom culture is already registered an unregistration is needed
    // otherwise the following Register() call will generate an exception
    if (CultureInfo.GetCultures(CultureTypes.UserCustomCulture).Where(ci => (ci.Name == customCulture)).Count() != 0)
    {
        // Admin rights are needed here
        CultureAndRegionInfoBuilder.Unregister(customCulture);
    }

    // Admin rights are needed here
    customCulture.Register();
}

Мне это хорошо работает, но в этом подходе есть две проблемы:

  1. В windows 7+ вам нужно запустить приложение с правами администратора, поскольку оно создаст новый файл культуры в C: \ Windows \ Globalization с именем, которое вы дадите своей пользовательской культуре
  2. Метод Unregister не удаляет указанный выше файл создания, но переименовывает его в xyz.tmp0 и, по логике, которую я не получил, время от времени создает больше копий файлов tmp (xyz.tmp1, xyz.tmp2, ...). По крайней мере, так работает на моем компьютере.

Что-то, что на самом деле не является проблемой, но немного странно, это то, что, как только я изменяю свои региональные настройки на панели управления, мне нужно дважды запустить приложение, прежде чем я увижу модификацию. Я могу выжить :)

...