Silverlight 4 Validator. Рюшечки
От: master_of_dp Беларусь  
Дата: 22.11.11 09:47
Оценка:
Hi, All.
После настойчивых обращений разъяренных пользователей на тему "почему я могу ввести пустую строку" в Silverlight 4 приложении, решил таки сделать "правильную" валидацию на формах ввода данных. Мудрые люди посоветовали воспользоваться DataAnnotations.
Собственно, сделал в ViewModel:
private string _name;
[Required(ErrorMessage = "Name is required.")]
public string Name
{
  get { return _name; }
  set  {
    if (_canValidate)
    {
       Validator.ValidateProperty(value,
                  new ValidationContext(this, null, null) { MemberName = "Name" });
    }
    _name = value;
    OnPropertyChanged("Name");
   }
}


Во View:
<TextBox Name="tbxName" Grid.Row="0" Grid.Column="1"   Margin="4"  MinWidth="160">
<TextBox.Text>
 <Binding Path="Name" ValidatesOnExceptions="True" ValidatesOnDataErrors="True" NotifyOnValidationError="True" ValidatesOnNotifyDataErrors="True"  Mode="TwoWay">
 </Binding>
</TextBox.Text>
</TextBox>


Запускаю, смотрю — ввел пустое значение в Name, перешел на другой контрол — все шикарно, Name подсветился красным, появился хинт "Name is required.". Просто праздник какой-то.
Но, думаю, надо ж как-то проверять не только при вводе в контрол, но и при сохранении данных (нажатии на кнопку Ok).
Делаю (по-быстрому) в форме:
private void OKButton_Click(object sender, RoutedEventArgs e)
{
  var mm = this.DataContext as ViewModel;
  try
  {
    mm.Validate();
    mm.UpdateModel();
    this.DialogResult = true;
  }
  catch ( ValidationException ex)
  {
   MessageBox.Show(ex.Message);
  }
}


А во ViewModel:
public void Validate()
{
  //Validator.ValidateObject(this, new ValidationContext(this, null, null), true);
  var errors = new List<ValidationResult>();
  var isValid = Validator.TryValidateObject(this, new ValidationContext(this, null, null), errors, true);
  if(!isValid)
  {
    throw new ValidationException( string.Join( Environment.NewLine,  errors.Select((e) => e.ErrorMessage )));
  }
}


Собственно система то валидирует, но красивых рюшечек с подстветкой НЕТ! Вопрос, можно ли как-то красиво пнуть систему, чтобы она делала подстветку валидации не только при обновлении пропертей, но и про "внейшей" проверке?

PS. Надеюсь понятно объяснил, чего хочу Все-таки бессонные ночи оставляют свой неизгладимый след...
Re: Silverlight 4 Validator. Рюшечки
От: master_of_dp Беларусь  
Дата: 22.11.11 13:25
Оценка:
Пока нашел тупое решение
1. Отказаться от Validator и перейти на INotifyDataErrorInfo
2. В View model Validate сделать принудительное обновление контролируемых свойств, что-то вроде

public bool Validate()
{
 Name = Name;
 if ( HasErrors) {
   MessageBox.Show("Validation failed" );
   return false;
 }
 return true;
}


Минус
— пока пропертя для сравнения надо руками прописывать (лень было автомат написать)
— почему-то хочется валидатор использовать.

Но в целом — работает.
Re[2]: Silverlight 4 Validator. Рюшечки
От: demigor  
Дата: 28.11.11 17:11
Оценка:
Докопаться до сообщений об ошибках в контролях SL практически нереально. Единственное, что работает — это принудительный байндинг с exception в сеттере.

Даю свой вариант установки любого графического контроля в режим ошибки:

public static class UX
{
    #region Error Property

    public static string GetError(DependencyObject obj)
    {
      return (string)obj.GetValue(ErrorProperty);
    }

    public static void SetError(DependencyObject obj, string value)
    {
      obj.SetValue(ErrorProperty, value);
    }

    static readonly DependencyProperty ErrorFlagProperty = DependencyProperty.RegisterAttached("ErrorFlag", typeof(object), typeof(UX), null);
    public static readonly DependencyProperty ErrorProperty = DependencyProperty.RegisterAttached("Error", typeof(string), typeof(UX), new PropertyMetadata(OnErrorChanged));

    static void OnErrorChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
      var control = obj as Control;
      if (control == null) return;

      if (args.NewValue == null)
        obj.ClearValue(ErrorFlagProperty);
      else
      {
        var binding = new Binding("Error")
        {
          Mode = BindingMode.TwoWay,
          NotifyOnValidationError = true,
          ValidatesOnExceptions = true,
          UpdateSourceTrigger = UpdateSourceTrigger.Explicit,
          Source = new ErrorMessage((string)args.NewValue)
        };

        BindingOperations.SetBinding(obj, ErrorFlagProperty, binding);

        control.GetBindingExpression(ErrorFlagProperty).UpdateSource();
      }
    }

    public class ErrorMessage
    {
      readonly string _error;

      public ErrorMessage(string error)
      {
        _error = error;
      }

      public string Error
      {
        get
        {
          return _error;
        }
        set
        {
          throw new Exception(_error);
        }
      }
    }

    #endregion
}


Работает так:
UX.SetError(_myEditBox, "Товарищи! Не забываем вводить парол");
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.