2011-12-21 3 views
0

Я хотел бы расширить некоторые стандартные UIElements в моем WPF. В идеале было бы хорошим решением использовать приложенные свойства. Но мне это не удалось.Прикрепленное свойство, связанное с перечнем через конвертер

В моей ViewModel Я коллекцию пользовательских объектов:

 private ObservableCollection<ValidationFailure> validationFailures = new ObservableCollection<ValidationFailure>(); 
    public ObservableCollection<ValidationFailure> ValidationFailures 
    { 
     get { return validationFailures; } 
     set 
     { 
      validationFailures = value; 
      OnPropertyChanged(() => ValidationFailures); 
     } 
    } 

Это то, что я хотел бы связать с моей Attached собственности. На мой взгляд, я также связываю его как ItemSource ListBox. Он показывает изменения и все правильно, поэтому я думаю, что сборник хорошо уведомляет.

На мой взгляд, я связываю это с помощью следующего кода:

<TextBox x:Name="ssn" Grid.Row="0" Grid.Column="1" Margin="10,0,0,0" 

        Text="{Binding PatientAggRoot.Patient.Ssn}" 
        Background="{Binding Path=CheckSsnButtonBackground}" 

        Validation:ValidationErrorAttached.HasValidationErrors="{Binding ValidationFailures,Converter={x:Static Converters:ConvertersHolder.ValidationErrorsLookupConverter},ConverterParameter='SSN',Mode=OneWay}" 
            /> 

Мой конвертер выглядит как эти:

public class ValidationErrorsLookupConverter : IValueConverter 
{ 
    #region IValueConverter implementation 
    public object Convert(object value, Type targetType, 
          object parameter, CultureInfo culture) 
    { 
     if (value != null) 
     { 
      var validationLookup = (ObservableCollection<ValidationFailure>)value; 
      bool hasErrors = validationLookup.Any(vf => vf.Key == ((string) parameter)); 
      return hasErrors; 
     } 

     return null; 
    } 

    public object ConvertBack(object value, Type targetType, 
           object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException("Can't convert back"); 
    } 
    #endregion 
} 

Я тестировал параметр преобразователя, он также работает должным образом с ListBox; Наконец мое вложенное свойство:

public static readonly DependencyProperty HasValidationErrorsProperty = DependencyProperty.RegisterAttached("HasValidationErrors", typeof(Boolean), typeof(ValidationErrorAttached), new FrameworkPropertyMetadata(true,  FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnChangeCallBack, OnCoerceValueChanged)); 

    private static object OnCoerceValueChanged(DependencyObject d, object basevalue) 
    { 
     //throw new NotImplementedException(); 
     return basevalue; 
    } 

    private static void OnChangeCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     //throw new NotImplementedException(); 
     if (((bool)e.NewValue)) 
     { 
      ((TextBox) d).BorderBrush = Brushes.Red; 
     } 
    } 

    public static void SetHasValidationErrors(UIElement element, Boolean value) 
    { 
     element.SetValue(HasValidationErrorsProperty, value); 
    } 
    public static Boolean GetHasValidationErrors(UIElement element) 
    { 
     return (Boolean)element.GetValue(HasValidationErrorsProperty); 
    } 

Он находится в классе ValidationErrorAttached, который является Freezable класса.

Когда я открываю форму, содержащую текстовое поле выше, coervalue Attached Property запускается 2 раза, меняет обратный вызов один раз, но после того, как (форма загружена), я меняю коллекцию на своей виртуальной машине и на основе коллекции конвертер изменит возвращаемое значение, подключенные свойства обратных вызовов не срабатывают, как я ожидал. Что я не так?

+0

У вас есть ошибки проверки по умолчанию? –

+0

Вообще-то может быть, но не в моем тестовом примере: Вскоре нет. но коллекция не является нулевой, просто пустой. –

+0

Это похоже на проблему, она собирает событие Collection.Add? –

ответ

1

Вы коллекцию Observable необходимо создать как DP. Beeing только свойство CLR, оно не способно сообщать о своих элементах Добавление и удаление событий, оно сообщает только о всех наборах свойств.

В основном ваше свойство CLR должно быть не более чем оберткой для вашего ObservableCollection < ..> Зависимость. Не забудьте инициализировать его либо в constrcutor, либо прямо из вашей декларации DP.

0

Конвертер будет работать ТОЛЬКО, если изменяется исходное свойство. Это означает, что событие PropertyChanged контекста создается для свойства ValidationFailures.

В вашем случае вы ожидаете, что автоматически произойдет для каждого ValidationFailures.Add(). Наблюдаемая коллекция может уведомлять изменения коллекции и изменения свойств для своих собственных свойств, таких как Count. Но они не будут автонотизировать свойство, которое содержит коллекцию как ее ценность.

Либо вы должны поднять OnPropertyChanged("ValidationFailures") после каждого ValidationFailures.Add() или изменить логику рычаги наблюдаемости в i.e.e ValidationFailures путем обработки коллекции измененного события наблюдаемой коллекции.

Решение 1:

Я предлагаю вам создать функцию в вашей модели вид patientMainViewModel.

void CheckAndValidate() 
    { 
     this.ValidationFailures.Clear(); 
     int parse; 
     if (!Int32.TryParse(
       this.PatientAggRoot.Patient.Ssn, out parse)) 
     { 
      this.ValidationFailures.Add(
        new ValidationFailure("SSN", "Taj szám nem csak számokból áll")); 
      this.OnPropertyChanged("ValidationFailures"); 
     } 
    } 

Решение 2

Избавьтесь от преобразователя и сделать ваше вложенное свойство делать все ставки.

public static readonly DependencyProperty ValidationErrorsProperty 
     = DependencyProperty.RegisterAttached(
      "ValidationErrors", 
      typeof(ObservableCollection<ValidationFailure>), 
      typeof(ValidationErrorAttached), 
      new FrameworkPropertyMetadata(new ObservableCollection<ValidationFailure>(), OnChangeCallBack)); 

    private static void OnChangeCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var list = (ObservableCollection<ValidationFailure>)e.NewValue; 
     if (list != null) 
     { 
      list.CollectionChanged += 
       delegate(
        object sender, 
        System.Collections.Specialized.NotifyCollectionChangedEventArgs arg) 
        { 
         if (list.Count == 0) 
         { 
          ((TextBox) d).BorderBrush = null; 
         } 
         else 
         { 
          ((TextBox) d).BorderBrush = new SolidColorBrush(Colors.Red); 
         } 
        }; 
     } 
    } 

    public static void SetValidationErrors(DependencyObject element, ObservableCollection<ValidationFailure> value) 
    { 
     element.SetValue(ValidationErrorsProperty, value); 
    } 

    public static ObservableCollection<ValidationFailure> GetValidationErrors(DependencyObject element) 
    { 
     return (ObservableCollection<ValidationFailure>)element.GetValue(ValidationErrorsProperty); 
    } 

Сообщите мне, если вам нужна дополнительная помощь.

Смежные вопросы