Покажите ошибку, если широта или долгота имеют неправильное форматирование

1

В моем приложении WPF есть диалог, в котором пользователь может ввести широту и долготу. Я написал IValueConverter который может обрабатывать значения, введенные как десятичные градусы, так и в градусах-минутах-второй формат:

[ValueConversion( typeof( double? ), typeof( string ) )]
public class CoordinateConverter : IValueConverter {

    #region IValueConverter Members

    public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) {
        double angle = 0.0;

        if ( value is string ) {
            if ( !double.TryParse( value as string, NumberStyles.Float, CultureInfo.InvariantCulture, out angle ) ) {
                return value;
            }

        } else if ( value is double || value is double? ) {
            angle = (double) value;

        } else {
            return value.ToString();
        }

        bool isNegative = angle < 0;
        if ( isNegative ) angle = -angle;

        double degrees   = Math.Truncate( angle );
        double remainder = ( angle - degrees ) * 60.0;
        double minutes   = Math.Truncate( remainder );
        double seconds   = ( remainder - minutes ) * 60.0;

        string result = degrees.ToString( "##0", culture.NumberFormat ) + "° " +
                        minutes.ToString( "#0", culture.NumberFormat ) + "' " +
                        seconds.ToString( "#0.00", culture.NumberFormat ) + "\" ";

        // The parameter contains "NS" for Latitudes and "EW" for Longitudes.
        if ( parameter != null ) {
            result += ( (string) parameter ).Substring( ( isNegative ? 1 : 0 ), 1 );
        } else {
            result = ( isNegative ? "-" : string.Empty ) + result;
        }

        return result;
    }

    public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) {
        string strValue = value as string;

        if ( string.IsNullOrEmpty( strValue ) ) {
            return null;
        }

        double adjustForSign = 1.0;
        if ( strValue.IndexOf( "-" ) >= 0 ) {
            adjustForSign = -1.0;
            strValue = strValue.Substring( strValue.IndexOf( "-" ) + 1 );
        }

        // Parse the value in the field.  It in three parts:  Degrees, minutes & seconds
        int degreeSymbol = strValue.IndexOf( "°" );
        int minuteSymbol = strValue.IndexOf( "'" );
        int secondSymbol = strValue.IndexOf( '"' );

        string degrees = null, minutes = null, seconds = null;
        double angle, d, m, s;

        if ( degreeSymbol < 0 ) {
            if ( double.TryParse( strValue, NumberStyles.Number, culture.NumberFormat, out angle ) ) {
                return angle;
            } else {
                return value;
            }

        } else {
            degrees = strValue.Substring( 0, degreeSymbol );

            if ( minuteSymbol >= 0 ) {
                minutes = strValue.Substring( degreeSymbol + 2, minuteSymbol - degreeSymbol - 2 );
            }
            if ( secondSymbol < 0 ) {
                seconds = "0" + culture.NumberFormat.NumberDecimalSeparator + "0";
            } else {
                seconds = strValue.Substring( minuteSymbol + 2, secondSymbol - minuteSymbol - 2 );
            }
        }

        if ( !double.TryParse( degrees, NumberStyles.Integer, culture.NumberFormat, out d ) ) return value;
        if ( !double.TryParse( minutes, NumberStyles.Integer, culture.NumberFormat, out m ) ) return value;
        if ( !double.TryParse( seconds, NumberStyles.Float  , culture.NumberFormat, out s ) ) return value;
        angle = d + m / 60.0 + s / 3600.0;

        if ( parameter != null ) {
            if ( strValue.Contains( ( (string) parameter ).Substring( 1, 1 ) ) ) {
                angle = -angle;
            }
        } else {
            angle *= adjustForSign;
        }
        return angle;
    }

В диалоговом окне я использую этот ControlTemplate для отображения ошибок:

<ControlTemplate x:Key="InputErrorTemplate">
    <DockPanel LastChildFill="True">
        <Image DockPanel.Dock="Right"
               Height="20"
               Margin="-30,0,0,0"
               Source="{StaticResource ErrorImage}"
               ToolTip="{x:Static res:Car.Common_InvalidData}"
               VerticalAlignment="Center"
               Width="20" />
        <Border BorderBrush="Red"
                BorderThickness="5"
                Margin="5,0,30,0">
            <AdornedElementPlaceholder />
        </Border>
    </DockPanel>
</ControlTemplate>

Если у одного из TextBoxes есть строка, например, она не анализируется, никакие исключения не выбрасываются, и отображается мой шаблон ошибки диалога. Когда я наводил указатель мыши на TextBox, отображается сообщение об ошибке: "Строка ввода не в правильном формате"

У меня есть пара вопросов:

  1. Откуда это сообщение об ошибке? Это не в моем коде, и если преобразователь выдает исключение, программа умирает, поскольку он необработан.
  2. В конце концов, я хочу показать ошибку, если значение в TextBox не может быть проанализировано. В диалоговом представлении View Model реализуется IDataErrorInfo, но преобразование из строки в double не выполняется этим объектом. Как это сделать?
Теги:
wpf

2 ответа

0
Лучший ответ

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

  • Вы можете создать собственное правило валидации
  • Вы можете вернуть validationresult из конвертера (хотя проверка и преобразование IMO действительно не совпадают)
  • Вы можете использовать интерфейс IDataError и MVVM

Вот несколько ссылок, которые содержат некоторую полезную информацию:

Еще одна вещь, при преобразовании ввода в double, есть ли какая-то конкретная причина использовать инвариантную культуру вместо культуры, переданной как параметр? Это может закончиться не-английской культурой (например, датской), где десятичный разделитель является запятой (что эквивалентно тысячам разделителей в английской культуре).

  • 0
    В моем приложении есть несколько классов IValueConverter , некоторым из которых передаются данные, проанализированные из файла XML, который кодирует все, используя инвариантную культуру. Недавно я добавил value is string регистр для обработки этих данных для всех преобразователей. Однако этому конкретному классу может не понадобиться эта логика. Я должен подумать об этом.
  • 0
    Кстати, этот диалог использует MVVM, а модель представления реализует интерфейс IDataError . Я не упомянул об этом в вопросе, потому что это казалось неуместным - на мой взгляд, вопрос был о IValueConverter а не о модели представления. Отображение широты и долготы в градусах, минутах и секундах не имеет ничего общего с проверкой допустимости введенных значений. И да, рассматриваемые свойства являются двойными. Чтобы выполнить эту проверку в модели представления, я должен был бы привязать текстовые поля к строковым свойствам и выполнить преобразование, чтобы удвоить их там. Не плохая идея, я мог бы добавить.
0

Поиграв с этим некоторое время, я обнаружил, что привязка, похоже, пытается ConvertBack любое значение, ConvertBack методами Convert или ConvertBack в правильный тип, основанный на данных направления. Если значение не может быть введено в этот тип, в сборку ошибок для этого элемента управления добавляется сообщение "Строка ввода не в правильном формате". Поэтому, если мой код просто возвращает исходное значение без изменений, если есть проблема, я получаю это сообщение.

Это сообщение достаточно хорошее, по крайней мере на данный момент. Если я хочу другое сообщение, мне придется исследовать создание правила проверки или какого-либо другого механизма.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню