public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                Debug.Write(GetType().Name + $".ConvertBack.value: \"{value}\" to ");
                object ret = null;

                string text = (string)value;

                // Получение парсера для типа в первой привязке (привязка к Источнику).
                TryParseNumberHandler tryParse = NumericTryParse.GetTryParse(targetTypes[0]);

                // Если парсер получить не удалось, значит первая привязка получила значение недопустимого типа.
                if (tryParse == null)
                {
                    throw InvalidTargetNumberType;
                }

                // Получение цифрового стиля из параметра. Если он не задан, то используется стиль по умолчанию для этого типа.
                NumberStyles style = NumericTryParse.GetNumberStyle(parameter, targetTypes[0]);

                // Получение из строки числа заданного типа в заданной культуре
                // Если удалось, то оно возвращается.
                if (tryParse(text, style, culture, out object target))
                {
                    ret = target;
                }

                Debug.WriteLine($"return: {(ret == null ? "null" : target)}");

                // Возвращается массив с одним элементом: полученным числом или null.
                return(new object[] { ret });
            }
Esempio n. 2
0
        public virtual object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            Debug.Write(GetType().Name + $".ConvertBack.value: \"{value}\" to ");
            object ret = null;

            // Полученной значение может быть только строкой или null.
            if (value != null && value.GetType() != typeof(string))
            {
                throw InvalidValueType;
            }

            // Если получен null или строка из пробелов, то используется "0".
            string text = (string)value;

            if (string.IsNullOrWhiteSpace(text))
            {
                text = "0";
            }

            // Должно быть две и только две привязки.
            if (targetTypes?.Length != 2)
            {
                throw InvalidNumberTargets;
            }

            // Получение парсера для типа в первой привязке (привязка к Источнику).
            TryParseNumberHandler tryParse = NumericTryParse.GetTryParse(targetTypes[0]);

            // Если парсер получить не удалось, значит первая привязка получила значение недопустимого типа.
            if (tryParse == null)
            {
                throw InvalidTargetNumberType;
            }

            // Тип значения по второй привязке (сравниваемый текст) должен быть только string.
            if (targetTypes[1] != typeof(string))
            {
                throw InvalidTargetStringType;
            }

            // Получение цифрового стиля из параметра. Если он не задан, то используется стиль по умолчанию для этого типа.
            NumberStyles style = NumericTryParse.GetNumberStyle(parameter, targetTypes[0]);

            // Получение из полученного значения числа заданного типа в заданной культуре
            // Если удалось, то оно возвращается.
            if (tryParse(text, style, culture, out object target))
            {
                ret = target;
            }


            Debug.WriteLine($"return: {ret ?? "null"}");

            // Если ret значение не присваивалось, то значит строка некорректна
            // Тогда возвращается null, что вызывает ошибку валидации.
            if (ret == null)
            {
                return(null);
            }

            // Иначе возвращается массив с одним элементом: полученным числом.
            return(new object[] { ret });
        }
Esempio n. 3
0
        public virtual object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            Debug.Write(GetType().Name + $".Convert.values: {values[0]}, \"{values[1]}\"");
            object ret = null;

            // Целевой тип должен быть или строкой или object.
            if (targetType != typeof(string) && targetType != typeof(object))
            {
                throw InvalidTargetType;
            }

            // Должно передаваться две и только две привязки.
            if (values?.Length != 2)
            {
                throw InvalidNumberValues;
            }

            // Получение парсера для типа в первой привязке (привязка к Источнику).
            TryParseNumberHandler tryParse = NumericTryParse.GetTryParse(values[0]?.GetType());

            // Если парсер получить не удалось, значит первая привязка получила значение недопустимого типа.
            if (tryParse == null)
            {
                throw InvalidNumberType;
            }
            object source = values[0];

            // Тип значения по второй привязке (сравниваемый текст) должен быть только string.
            if (values[1]?.GetType() != typeof(string))
            {
                throw InvalidStringType;
            }
            string text = (string)values[1];

            // Получение цифрового стиля из параметра. Если он не задан, то используется стиль по умолчанию для этого типа.
            NumberStyles style = NumericTryParse.GetNumberStyle(parameter, values[0].GetType());

            // Получение из строки (во второй привязке) числа в том же типе, что получено от Источника (в первой привязке).
            // И сравнение этого числа с числом Источника.
            if (tryParse(text, style, culture, out object target) && target.Equals(source))
            {
                // Если числа равны, то проверяется наличие крайних пробелов в строке.
                // Если пробелов нет, то отменяется присвоение значения привязкой.
                string trim = text.Trim();
                if (trim == text)
                {
                    ret = Binding.DoNothing;
                }

                // Иначе присваивается строка с удалёнными крайними пробелами.
                else
                {
                    ret = trim;
                }
            }

            // Если из строки не удалось получить число, или это число не равно числу Источника,
            // то возвращается число Источника в текстовом виде в заданной культуре.
            else
            {
                ret = System.Convert.ToString(source, culture);
            }


            Debug.WriteLine($"; return: {ret ?? "null"}");
            return(ret);;
        }
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                object ret = null;

                object source = values[0];

                if (source == DependencyProperty.UnsetValue)
                {
                    return(source);
                }

                TextBox textBox = (TextBox)values[1];
                string  newText = textBox.Text;

                // Получение состояния привязки TextBox
                TextBoxBindingState bindingState = GetBindingState(textBox);
                string oldText = bindingState.OldText;

                // Получение парсера для типа в первой привязке (привязка к Источнику).
                TryParseNumberHandler tryParse = NumericTryParse.GetTryParse(source.GetType());

                // Если парсер получить не удалось, значит первая привязка получила значение недопустимого типа.
                if (tryParse == null)
                {
                    throw InvalidNumberType;
                }

                Debug.Write(GetType().Name + $".Convert.values: {source}, \"{oldText}\", \"{newText}\"");

                // Получение цифрового стиля из параметра. Если он не задан, то используется стиль по умолчанию для этого типа.
                NumberStyles style = NumericTryParse.GetNumberStyle(parameter, values[0].GetType());

                // Проверка причины вызова конвертера.
                switch (bindingState.UpdateSourceState)
                {
                // Метод UpdateSource() не вызывался, значит значение обновляется по привязке от Источника.
                case UpdateSourceStateEnum.NotCalled:

                    // Получение из TextBox числа в том же типе, что получено от Источника (в первой привязке).
                    // И сравнение этого числа с числом Источника.
                    if (tryParse(newText, style, culture, out object target) && target.Equals(source))
                    {
                        // Отменяется присвоение значения привязкой.
                        ret = Binding.DoNothing;
                    }

                    // Иначе возвращается число Источника в текстовом виде в заданной культуре.
                    else
                    {
                        ret = System.Convert.ToString(source, culture);
                    }
                    break;

                // Обновление источника произошло в ходе выполнения метода UpdateSource().
                // Значит в TextBox.Text корректное значение и его надо проверить только на крайние пробелы
                // для режима ввода "Tолько Числа".
                case UpdateSourceStateEnum.Called:
                    if (bindingState.IsNumericOnly)
                    {
                        if (newText.Length < 1 || char.IsWhiteSpace(newText[0]) || char.IsWhiteSpace(newText[newText.Length - 1]))
                        {
                            // Устанавливается флаг обновления по привязке
                            bindingState.TextChangeSource = PropertyChangeSourceEnum.Binding;
                            // Возращается TextBox старое значение.
                            UndoText(textBox, oldText, bindingState.Changes);
                        }
                    }
                    // Отменяется присваивание.
                    ret = Binding.DoNothing;

                    break;

                // После вызова UpdateSource() обновление источника не произошло
                // Значит в TextBox.Text некорректное значение и надо вернуть предыдущее его значение.
                case UpdateSourceStateEnum.CallCanceled:

                    // Устанавливается флаг обновления из конвертера привязки
                    bindingState.TextChangeSource = PropertyChangeSourceEnum.Binding;

                    // Проверяется на пустую строку.
                    // Если она пустая, то надо её заменить на "0".
                    // Это автоматически сделает метод UndoText().
                    if (string.IsNullOrWhiteSpace(newText))
                    {
                        ZeroText(textBox);
                    }

                    else if (!BeginScientific(newText))
                    {
                        // Возращается TextBox старое значение.
                        UndoText(textBox, oldText, bindingState.Changes);
                    }

                    // Сброс флага обновления из конвертера привязки
                    bindingState.TextChangeSource = PropertyChangeSourceEnum.NotBinding;

                    // Проверка строки в TextBox.
                    // Если она корректна, то для сброса валидации надо её же и вернуть
                    if (tryParse(textBox.Text, style, culture, out _))
                    {
                        ret = textBox.Text;
                    }
                    else
                    {
                        // Иначе - отмена присвоения по привязке
                        ret = Binding.DoNothing;
                    }

                    break;

                default:
                    break;
                }

                Debug.WriteLine($"; return: {ret ?? "null"}");

                if (ret is string str && str != textBox.Text)
                {
                    // Устанавливается флаг обновления по привязке
                    bindingState.TextChangeSource = PropertyChangeSourceEnum.Binding;
                }

                return(ret);;

                // Проверка строки на начало научной записи числа
                bool BeginScientific(string text)
                {
                    if (string.IsNullOrWhiteSpace(text))
                    {
                        return(false);
                    }
                    if (style.HasFlag(NumberStyles.AllowExponent))
                    {
                        if (text[text.Length - 1] == 'e' || text[text.Length - 1] == 'E')
                        {
                            text = text.Remove(text.Length - 1, 1);
                        }
                        else if (text.Length > 1 && (text[text.Length - 1] == '-' || text[text.Length - 1] == '+') &&
                                 (text[text.Length - 2] == 'e' || text[text.Length - 2] == 'E'))
                        {
                            text = text.Remove(text.Length - 2, 2);
                        }
                    }
                    return(tryParse(text, style, culture, out _));
                }
            }