Dot-Net

將 DataContext 綁定到 ValidationRule

  • February 3, 2015

我有一個自定義 ValidationRule 需要訪問 ViewModel 以驗證提供的值以及 ViewModel 的其他屬性。我以前嘗試通過使用 ValidationGroup 來實現這一點,但放棄了這個想法,因為我正在修改的程式碼需要大量重構才能啟用這條路線。

在新聞組上找到了一個執行緒,該執行緒顯示了一種將控制項的 DataContext 綁定的方法,其中 ValidationRule 通過從 DependencyObject 繼承的中間類執行到該 ValidationRule,但我無法將其綁定。

有人可以幫忙嗎?

我的 ValidationRule 如下…

class TotalQuantityValidator : CustomValidationRule {

   public TotalQuantityValidator()
       : base(@"The total number must be between 1 and 255.") {
   }

   public TotalQuantityValidatorContext Context { get; set; }

   public override ValidationResult Validate(object value, CultureInfo cultureInfo) {

       ValidationResult validationResult = ValidationResult.ValidResult;

       if (this.Context != null && this.Context.ViewModel != null) {

           int total = ...
           if (total <= 0 || total > 255) {
               validationResult = new ValidationResult(false, this.ErrorMessage);
           }

       }

       return validationResult;

   }

}

CustomValidationRule 定義如下…

public abstract class CustomValidationRule : ValidationRule {

   protected CustomValidationRule(string defaultErrorMessage) {
       this.ErrorMessage = defaultErrorMessage;
   }

   public string ErrorMessage { get; set; }

}

TotalQuantityValidatorContext 定義如下…

public class TotalQuantityValidatorContext : DependencyObject {

   public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(@"ViewModel",
       typeof(MyViewModel), typeof(TotalQuantityValidatorContext),
       new PropertyMetadata {
           DefaultValue = null,
           PropertyChangedCallback = new PropertyChangedCallback(TotalQuantityValidatorContext.ViewModelPropertyChanged)
       });

   public MyViewModel ViewModel {
       get { return (MyViewModel)this.GetValue(TotalQuantityValidatorContext.ViewModelProperty); }
       set { this.SetValue(TotalQuantityValidatorContext.ViewModelProperty, value); }
   }

   private static void ViewModelPropertyChanged(DependencyObject element, DependencyPropertyChangedEventArgs args) {
   }

}

整個事情就是這樣使用的……

<UserControl x:Class="..."
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:val="clr-namespace:Validators" x:Name="myUserControl">

   <TextBox Name="myTextBox">
       <TextBox.Text>
           <Binding NotifyOnValidationError="True" Path="myViewModelProperty" UpdateSourceTrigger="PropertyChanged">
               <Binding.ValidationRules>
                   <val:TotalQuantityValidator>
                       <val:TotalQuantityValidator.Context>
                           <val:TotalQuantityValidatorContext ViewModel="{Binding ElementName=myUserControl, Path=DataContext}" />
                       </val:TotalQuantityValidator.Context>
                   </val:TotalQuantityValidator>
               </Binding.ValidationRules>
           </Binding>
       </TextBox.Text>
   </TextBox>

</UserControl>

UserControl 的 DataContext 在程式碼隱藏中被設置為 MyViewModel 的一個實例。我知道此綁定的工作原理是標準控制項綁定按預期執行。

TotalQuantityValidator.Validate方法被正確呼叫,但每當我查看 的ViewModel屬性時Context,它始終為空( 的Context屬性被正確TotalQuantityValidator設置為 的實例TotalQuantityValidatorContext)。我可以從調試器中看到,永遠不會呼叫ViewModel屬性上的設置器。TotalQuantityValidatorContext

任何人都可以建議我如何讓這個綁定工作嗎?

提前致謝。

我會避免使用驗證規則。如果您需要訪問 viewmodel 中的資訊來執行驗證,那麼最好將驗證邏輯放在 viewmodel 本身中。

您可以讓您的視圖模型實現IDataErrorInfo,並簡單地在綁定上打開基於數據錯誤資訊的驗證。

即使您沒有遇到需要上下文資訊的(非常常見的)問題,驗證規則也不是表達驗證的好方法:驗證規則通常與業務邏輯相關,或者至少與資訊的語義方面相關. Xaml 似乎是放置這些東西的錯誤位置 - 為什麼我要在源文件中放置一個業務規則,其主要工作是確定我的應用程序的佈局和視覺設計?

驗證邏輯屬於您的應用程序的更下方。甚至視圖模型也可能是錯誤的層,但在這種情況下,您可以簡單地讓視圖模型負責確定在哪裡找到驗證邏輯。

引用自:https://stackoverflow.com/questions/4345606