Текст на Textbox с помощью UpdateSourcetrigger = ProperateChanged не обновляется, когда принуждение текстового ввода приводит к неизменному значению источника

StackOverflow https://stackoverflow.com/questions/4128567

Вопрос

У меня есть текстовое поле, чье Текст Собственность имеет Двойной Многобинд с Updatesourcetrigger установлен в Propertychanged. Анкет Первое Связывание к свойству зависимости (Ценность), который имеет PropertyChangedCallback функция, которая окружает значение до одного десятичного места.

Цель текстового поля состоит в том, чтобы выполнить округление как типы пользователей, а не когда текстовое поле теряет фокус, поэтому почему Updatesourcetrigger установлен на Propertychanged.

Проблема, которая у меня возникает, заключается в том, что если введен текст, это не приводит к Ценность изменение, Текст собственность и Ценность стать вне синхронизации. Только если операция округления вызывает Ценность изменить делает Текст Получите обновление на лету. Например, если Текст и Ценность оба 123,4, так и пользователи типа 1 после этого, Ценность округлен до того же значения (123,4), но Текст показывает 123,41. Однако, если 9 затем печатается после 4, Ценность округлен до 123,5. И из -за этого фактического изменения, Текст затем обновляется до того же (123,5).

Есть ли какой -нибудь способ привязать текстовое поле обновить из своего источника, даже если источник не изменился с момента последнего триггера? Я пытался использовать BindingExpressionBase.UpdateTarget() Но это работает только тогда, когда Updatesourcetrigger установлен на Явный, который не может быть использован как Ценность больше не обновляется до подходящего времени, когда UpdateTarget можно назвать (например Ввод текста обработчик). Я пробовал другие методы, такие как явное обновление Текст значение из границы Ценность, принуждая фактическое изменение в Ценность Временно, чтобы вызвать обновление, но эти «взломы» либо не работают, либо вызывают другие проблемы.

Любая помощь будет очень оценена.

Код ниже.

XAML фрагмент

<TextBox>
  <TextBox.Text>
    <MultiBinding Converter="{local:NumberFormatConverter}"
                  UpdateSourceTrigger="Explicit"
                  Mode="TwoWay">
      <Binding Path="Value"
               RelativeSource="{RelativeSource AncestorType={x:Type Window}}"
               Mode="TwoWay" />
    </MultiBinding>
  </TextBox.Text>
</TextBox>

C# фрагмент

public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register(
        "Value", typeof(decimal), typeof(MainWindow),
        new FrameworkPropertyMetadata(0m,
        new PropertyChangedCallback(OnValueChanged)));

private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
    obj.SetValue(ValueProperty, Math.Round((decimal)args.NewValue, 1));
}

Требуется класс конвертера

public class NumberFormatConverter : MarkupExtension, IMultiValueConverter
{
    public static NumberFormatConverter Instance { private set; get; }

    static NumberFormatConverter()
    {
        Instance = new NumberFormatConverter();
    }

    public override object ProvideValue(IServiceProvider serviceProvider_)
    {
        return Instance;
    }

    #region Implementation of IMultiValueConverter

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return values[0].ToString();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        var result = 0m;
        if (value != null)
        {
            decimal.TryParse(value.ToString(), out result);
        }
        return new object[] { result };
    }

    #endregion
}
Это было полезно?

Решение

Я немного копал в Интернете, и оказывается, что это было сломано в WPF 4. Кто-то с почти идентичной проблемой для меня опубликовал здесь:http://www.go4answers.com/example/textbox-shows ald-value-being-coerced-137799.aspx

«Ответ 8» утверждает, что это было сломано в WPF 4 и предлагает решение, которое фактически использовать UpdateSourceTrigger="Explicit" Но чтобы справиться с событием TextChange и позвонить BindingExpression.updatesource () Чтобы заставить изменения в текстовом поле отражать в базовом значении, как если бы UpdateSourceTrigger="PropertyChanged", согласно этому посту:Приступите текстовое поле WPF больше не работает в .net 4.0

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

Следующий обработчик событий - это все, что было необходимо:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    var tb = (TextBox)e.Source;
    MultiBindingExpression binding = BindingOperations.GetMultiBindingExpression(tb, TextBox.TextProperty);

    decimal result = 0m;
    decimal.TryParse(tb.Text, out result);

    if ((decimal)GetValue(ValueProperty) != result && binding != null)
    {
        int caretIndex = tb.CaretIndex;
        binding.UpdateSource();
        tb.CaretIndex = caretIndex;
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top