Есть ли лучший способ обработки двойных значений в разных языках? - PullRequest
1 голос
/ 05 февраля 2012

Прямо сейчас, чтобы приспособить использование запятых в качестве десятичных заполнителей в таких языках, как датский, я извлекаю значения, хранящиеся с десятичными точками, например ".123", из файла .resx, например:

// Getting a value from a .resx parameter
double minValue = Convert.ToDouble(AppParams.minVal, CultureInfo.InvariantCulture);

И когда мне нужно работать со значением, полученным из TextBox, например, ", 321", я использую это:

// Getting a value from a TextBox    
double newValue = Convert.ToDouble(value, CultureInfo.CurrentCulture);

В файле .csproj я добавил <SupportedCultures>da;</SupportedCultures>, но в противном случае не сделалпопытался применить к этим двум вопросам какой-то общепринятый способ, кроме того, что показано.

Ответы [ 3 ]

4 голосов
/ 05 февраля 2012

Вам не нужно сохранять значение в виде строки в файле resx:

<data name="minVal" type="System.Double, mscorlib">
    <value>.123</value>
</data>

Таким образом, сгенерированное свойство minVal будет иметь тип double, и у вас не будетпреобразовать его вручную.

Единственная проблема с этим подходом заключается в том, что вам необходимо вручную редактировать файл resx в XML, поскольку конструктор ресурсов не может обрабатывать ресурсы этого типа (на самом деле вы можете переименовать или удалитьресурса или измените его значение, но вы не можете изменить его тип и не можете создать новый).В любом случае, я переключился на ручное редактирование файла resx с тех пор, как начал использовать Resharper, потому что он предоставляет некоторые хорошие возможности анализа и рефакторинга для этих файлов;)

В качестве примечания, я не думаю, что это minValue константа - хороший кандидат на ресурсы.Если это настройка, которую можно изменить, поместите ее в настройках, а не в ресурсах.Если это действительно константа, сделайте это const в коде C #.Единственная веская причина поместить его в ресурсы, если вы хотите, чтобы значение было локализуемым, и в этом случае это маловероятно.

1 голос
/ 05 февраля 2012

Когда вы анализируете строку из пользовательского ввода, попробуйте принять много возможных входных данных, например,

public static class Helper
{
    public static bool TryParseDouble(this TextBox textbox, out double value)
    {
        if (double.TryParse(textbox.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
        {
            textbox.Foreground = Brushes.Black; //indicates that the user typed correct number
            return true;
        }
        else
        {
            textbox.Foreground = Brushes.Red; // not a number
            return false;
        }
    }
}

Когда вы анализируете .resx, XML и другие файлы, используйте также InvariantCulture. Здесь - проблема, с которой я столкнулся при синтаксическом анализаторе XML.

При отображении данных пользователю используйте текущую культуру.

0 голосов
/ 05 февраля 2012

Я очень ценю ответы Томаса Левеска и Лукаса.Они содержали некоторые полезные идеи и примеры.Я публикую это как ответ, потому что хочу предоставить больше информации и пример решения.Как и в случае многих проблем с вычислительной средой / пользовательским интерфейсом, часто приходится идти на компромиссы.Я сделал неудачное открытие, что ни одно из InputScopeNameValues ​​( MSDN InputScopeNameValue Enumeration ) не переключается между десятичным (.) И запятой (,) при изменении настроек языка + региона (и, да, я дважды проверил, что клавиатурана моем телефоне было установлено использование только Deutsch).

enter image description here

Однако, поскольку эти вводы TextBox являются числовыми и должны вводиться быстро, числовые InputScopes по-прежнему лучший способ,Интересно, что даже если пользователь вынужден использовать десятичную точку вместо запятой, как только она вводится в TextBox, формат строки изменяется, например, с «.123» на «, 123», даже если показано «{0».:. # 000}».Таким образом, компромисс и в приведенном ниже коде, обходной путь (проверено до сих пор в en-US и de-DE).

Примечание. Как упоминал Лукас, всегда целесообразно проверять вводимые пользователем данные.Я не использую здесь TryParse (хотя могу), поэтому мне не нужно переписывать много кода.Это смягчается в пользовательском интерфейсе путем выбора числового InputScope и в коде обработки через блоки try / catch, которые даже корректно обрабатывают пользователя, пытающегося обойти числовой ввод, вставляя текст из буфера обмена:

<TextBox x:Name="myTBox" InputScope="Number" Text="{Binding SomeNumber, Mode=TwoWay}" />

И код:

public string SomeNumber

{get {return String.Format ("{0: #. 000}", SomeProfileModel.Instance.SomeProfile.SomeNumber);}

set
{
    if (SomeProfileModel.Instance.SomeProfile.SomeNumber.ToString() == value) return;

    var oldValue = SomeProfileModel.Instance.SomeProfile.SomeNumber;

    try
    {
        double newValue;

        try
        {
            newValue = Convert.ToDouble(value, CultureInfo.CurrentCulture);
        }
        catch (Exception)
        {
            newValue = Convert.ToDouble(value, CultureInfo.InvariantCulture);
        }

        if (Convert.ToDouble(MyAppParams.SomeNumberMin, CultureInfo.InvariantCulture) > newValue || Convert.ToDouble(MyAppParams.SomeNumberMax, CultureInfo.InvariantCulture) < newValue)
        {
            // Revert back to previous value
            // NOTE: This has to be done here. If done in the catch statement, 
            // it will never run since the MessageBox interferes with it.
            throw new Exception();
        }

        SomeProfileModel.Instance.SomeProfile.SomeNumber = newValue;

        RaisePropertyChanged("SomeNumber", oldValue, newValue, true);
    }
    catch (Exception err)
    {
        System.Windows.MessageBox.Show("Value must be a number between " + MyAppParams.SomeNumberMin + " and " + MyAppParams.SomeNumberMax);
    }
}

}

...