2016-11-03 2 views
0

Моя проблема кажется простой, но я не нашел способ решить эту проблему. Итак, я здесь.BindingGroup CancelEdit не работает с UpdateSourceTrigger = "PropertyChanged"

Вот мой код.

<TextBox CharacterCasing="Upper"> 
    <TextBox.Text> 
     <Binding Path="nome" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay"> 
      <Binding.ValidationRules> 
       <ValidationRules:IsNotNull/> 
       <ValidationRules:MyStringLengthValidationRule Length="45"/> 
      </Binding.ValidationRules> 
     </Binding> 
    </TextBox.Text> 
</TextBox> 

Я использую bindgroup для фиксации и отмены моего редактирования. Но, когда я использую UpdateSourceTrigger="PropertyChanged", команда BindingGroup.CancelEdit() не работает. Зачем?

Я не могу удалить UpdateSourceTrigger="PropertyChanged", потому что с этим ValidationRules работают, когда текст был изменен.

+0

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

+0

Извините, была ошибкой. – StanleyIPC

+0

Намного лучше, спасибо. Это немного грубо на моем iPhone с дополнительным отступом, но я посмотрю, когда доберусь до офиса. –

ответ

1

Правила валидации применяются, когда целевое значение (TextBox.Text в этом случае) присваивается источнику (в этом случае свойство viewmodel). BindingGroup.CancelEdit() очищает состояние ошибки и копирует исходные значения в целевые свойства.

При установке UpdateSourceTrigger="PropertyChanged" на этом TextBox.TextBinding, на каждом нажатии клавиши в текстовом поле валидацию Binding работает на TextBox.Text, и если она проходит проверку, она копирует целевое значение для свойства источника. Это означает, что он копирует TextBox.Text в yourViewModel.nome.

Например, yourViewModel.nome изначально null.

Пользователь нажимает кнопку в текстовом поле и набирает «Арнольд». yourViewModel.nome обновляется шесть раз, пока пользователь печатает, один раз для каждого символа.

Пользователь нажимает кнопку Cancel, что вызывает вызов BindingGroup.CancelEdit().

BindingGroup.CancelEdit(), ведет себя как задумано, копирует значение тока из yourViewModel.nome, строка "Arnold", чтобы TextBox.Text.

Это проблема, которую вы видите.

С BindingGroup, проверка is фиксация. Если поле проверено и проходит проверку, оно выполняется. И как только вы совершите, слишком поздно отменять.

Если вы хотите повременить проверки и проверки/фиксации группы полей вместе, то вы используете BindingGroup и UpdateSourceTrigger="Explicit", что приводит к валидации/фиксация произойдет только на BindingGroup.CommitEdit(), или когда вы звоните UpdateSource() on the сам Binding`:

myTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); 

Лекция заканчивается, ответ начинается

Если вы хотите проверить без фиксации, вы будете иметь, чтобы сделать что-то немного другое.

Самого простое и самый простое, что нужно сделать, это установить UpdateSourceTrigger="Explicit" на креплениях и обрабатывать TextChanged на текстовых полях:

XAML

<TextBox CharacterCasing="Upper" TextChanged="anyValidatedTextBox_TextChanged"> 
    <TextBox.Text> 
     <Binding Path="nome" UpdateSourceTrigger="Explicit" Mode="TwoWay"> 
      <Binding.ValidationRules> 
       <ValidationRules:IsNotNull/> 
       <ValidationRules:MyStringLengthValidationRule Length="45"/> 
      </Binding.ValidationRules> 
     </Binding> 
    </TextBox.Text> 
</TextBox> 

Codebehind

private void anyValidatedTextBox_TextChanged(object sender, TextChangedEventArgs e) 
{ 
    (sender as TextBox) 
     .GetBindingExpression(TextBox.TextProperty) 
     .ValidateWithoutUpdate(); 
} 

или вы может сделать весь BindingGroup утвердить без изменений:

private void anyValidatedTextBox_TextChanged(object sender, TextChangedEventArgs e) 
{ 
    myFormStackPanel.BindingGroup.ValidateWithoutUpdate(); 
} 

Другой Ответ

Более обобщенный способ сделать это, более ортодоксальный MVVM, чтобы написать поведение, которое делает то же самое.

using System; 
using System.ComponentModel; 
using System.Windows; 

namespace HollowEarth.Behaviors 
{ 
    public static class Validation 
    { 
     #region Validation.OnPropertyChanged Attached Property 
     public static DependencyProperty GetOnPropertyChanged(FrameworkElement obj) 
     { 
      return (DependencyProperty)obj.GetValue(OnPropertyChangedProperty); 
     } 

     public static void SetOnPropertyChanged(FrameworkElement obj, DependencyProperty value) 
     { 
      obj.SetValue(OnPropertyChangedProperty, value); 
     } 

     public static readonly DependencyProperty OnPropertyChangedProperty = 
      DependencyProperty.RegisterAttached("OnPropertyChanged", typeof(DependencyProperty), typeof(Validation), 
       new PropertyMetadata(null, OnPropertyChanged_PropertyChanged)); 

     private static void OnPropertyChanged_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var obj = d as FrameworkElement; 

      if (e.OldValue != null) 
      { 
       DependencyPropertyDescriptor. 
        FromProperty(e.OldValue as DependencyProperty, obj.GetType()) 
        .RemoveValueChanged(obj, ValidateHandler); 
      } 

      if (e.NewValue != null) 
      { 
       DependencyPropertyDescriptor. 
        FromProperty(e.NewValue as DependencyProperty, obj.GetType()) 
        .AddValueChanged(obj, ValidateHandler); 
      } 
     } 

     static void ValidateHandler(object sender, EventArgs args) 
     { 
      var fe = (FrameworkElement)sender; 
      var dprop = GetOnPropertyChanged(fe); 
      fe.GetBindingExpression(dprop).ValidateWithoutUpdate(); 
     } 
     #endregion Validation.OnPropertyChanged Attached Property 
    } 
} 

XAML:

<TextBox 
    xmlns:hb="clr-namespace:HollowEarth.Behaviors" 
    CharacterCasing="Upper" 
    hb:Validation.OnPropertyChanged="{x:Static TextBox.TextProperty}" 
    > 
    <TextBox.Text> 
     <Binding Path="nome" UpdateSourceTrigger="Explicit" Mode="TwoWay"> 
      <Binding.ValidationRules> 
       <ValidationRules:IsNotNull/> 
       <ValidationRules:MyStringLengthValidationRule Length="45"/> 
      </Binding.ValidationRules> 
     </Binding> 
    </TextBox.Text> 
</TextBox> 

Я предпочел бы, что поведение применительно к BindingGroup или владелец BindingGroup «s, а не к отдельным полям, но когда я попробовал это, BindingGroup.BindingExpressions и BindingGroup.Items были пусты на момент его применения. BindingGroup не имеет событий, и в его коллекции нет событий. Бьюсь об заклад, вы можете что-то сделать с поведением владельца BindingGroup, где вы делаете крючки на LayoutUpdated, но мое внимание начинает блуждать. Я оставлю это как упражнение для ученика.

В качестве дополнительного упражнения вы можете просто скопировать и вставить мой код, даже не прочитав его. Вот что я делаю, девять раз из десяти.

+0

Awesome чувак. Кроме того, вы решаете, вы научили меня. Спасибо тебе за все! Чем я могу вам помочь? О себе «Я готов поспорить, что вы можете что-то сделать с поведением владельца BindingGroup, где вы зацепились за LayoutUpdated». Я не знаю, как это сделать :( – StanleyIPC

+0

@StanleyIPC Я немного испортил его, и оказалось, что это легко сделать плохо, но не совсем легко преуспеть. Если вам нужна помощь при запуске он даже не думает идти туда. То, что у меня есть, достаточно: если вы положите 'hb: Validation.OnPropertyChanged =" {x: Static TextBox.TextProperty} "на все текстовые поля в вашей группе привязки , он будет делать то, что вы хотите. Или вы могли бы просто пойти вперед и использовать идею события TextChanged, которую я предложил вначале. Любой из них будет работать, и ни разрывает MVVM. –