2011-12-21 78 views
0

我想在我的WPF中擴展一些標準的UIElements。理想情況下,使用附加屬性將是一個很好的解決方案。但我沒有設法做到這一點。通過轉換器綁定到列表的附加屬性

在我的ViewModel我有自定義對象的集合:

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

這是想什麼我綁定到我的附加屬性。在我看來,我也將它作爲ListBox的ItemsSource綁定。它顯示了變化,以及一切正常,這就是爲什麼我認爲收集通知良好。

在我看來,我用下面的代碼綁定它:

<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被激發了2次,更改了一次回調,但是當(表單被加載時)我更改了我的VM中的集合,並且基於集合轉換器改變返回值,附加的屬性回調不會像我預期的那樣觸發。我錯了什麼?

+0

您是否有默認的驗證錯誤? – 2011-12-21 09:54:58

+0

通常可以有,但不是在我的測試案例:很快沒有。但收集不是空的,只是空的。 – 2011-12-21 10:37:25

+0

這就像他們的問題 - 它拿起Collection.Add事件? – 2011-12-21 10:48:10

回答

1

您可以將Observable集合創建爲DP。 Beeing只是一個CLR屬性,它不能報告它的Items Add/Remove事件,它只報告有關整個屬性集。

基本上你的CLR屬性應該不會超過你的ObservableCollection的包裝< ..>依賴屬性。不要忘記在代理商或者你的DP聲明中對其進行初始化。

0

如果您的源屬性更改,轉換器將只運行。這意味着當上下文的PropertyChanged事件引發ValidationFailures屬性時。

在你的情況下,你期望自動發生每個ValidationFailures.Add()。可觀察集合可以通知他們自己的屬性收集更改和屬性更改,如Count。但他們不會將擁有該藏品的財產自行覈定爲其價值本身。

要麼你不得不提高每個ValidationFailures.Add()OnPropertyChanged("ValidationFailures")或更改你的邏輯通過處理觀察集合的集合變化的事件來利用ValidationFailures i.e.e的可觀測

解決方案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); 
    } 

讓我知道你是否需要任何幫助。