Прикрепленное свойство привязано к списку через конвертер - PullRequest
0 голосов
/ 21 декабря 2011

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

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

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

Это то, что я хотел бы привязать к своему приложенному свойству,На мой взгляд, я также связываю его как ItemsSource 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
}

Я протестировал параметр конвертера, он также правильно работает со списком;Наконец, мое прикрепленное свойство:

    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Иногда меняем колбэк один раз, но после того, как (форма загружена) я изменяю коллекцию в моей виртуальной машине, и на основе коллекции конвертер меняет возвращаемое значение, обратные вызовы присоединенного свойства не запускаются, как я ожидал.Что я не прав?

Ответы [ 2 ]

1 голос
/ 21 декабря 2011

Ваша наблюдаемая коллекция должна быть создана как DP.Будучи просто свойством CLR, он не может сообщать о своих событиях добавления / удаления элементов, он только сообщает обо всех наборах свойств.

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

0 голосов
/ 21 декабря 2011

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

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

Либо вам придется повышать OnPropertyChanged("ValidationFailures") после каждого ValidationFailures.Add(), либо изменять свою логику, чтобы использовать наблюдаемость из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);
    }

Дайте мне знать, если вынужна дополнительная помощь.

...