2012-07-25 65 views
0

編輯:這是此帖子原始版本的簡化更新。基於IDataErrorInfo的驗證不起作用

在WPF我實現了一個用戶控件(稱爲 'NumericTextBox'),其使用的a *的DependencyProperty '值' 被保持同步與文本框(XAML)的文本屬性:

<TextBox.Text> 
    <Binding Path="Value" 
      Mode="TwoWay" 
      ValidatesOnDataErrors="True" 
      NotifyOnValidationError="True" 
      UpdateSourceTrigger="PropertyChanged" /> 
</TextBox.Text> 

爲了驗證目的我使用IDataErrorInfo的接口(xaml.cs):

public partial class NumericTextbox : Textbox, IDataErrorInfo { 
    public double Value { 
     get { return (double)GetValue(ValueProperty); } 
     set { SetValue(ValueProperty, value); } 
    } 

    public static readonly DependencyProperty ValueProperty = 
     DependencyProperty.Register("Value", typeof(double), 
            typeof(NumericTextBox), 
            new PropertyMetadata(default(double))); 

    public string this[string columnName] 
    { 
     // Never gets called! 
     get { /* Some validation rules here */ } 
    } 
} 

正如在源代碼中所述,get屬性實際上是永遠不會被稱爲,因此沒有驗證發生。你看到問題的原因嗎?

編輯2:基於ethicallogics的答案我重構了我的代碼。該NumericTextBox現在使用的底層視圖模型類,它提供一個依賴屬性綁定到文本框這是由NumericTextBox宣佈的文本屬性。另外NumericTextBox使用viewmodel作爲其datacontext。 Viewmodel現在負責檢查Value屬性的更改。由於NumericTextBox的值限制是可定製的(例如,最小值可以調整),因此將這些設置轉發給視圖模型對象。

+0

什麼是您的問題? – harry180 2012-07-25 12:04:20

+0

對不起,剛更新了帖子。 – Bastian 2012-07-25 12:08:38

+0

所以你想檢查用戶是否只寫數字?我很好理解你的問題? – harry180 2012-07-25 12:14:35

回答

0

這樣做,而不是創建任何依賴屬性。 ViewModel不在Control或View中應用驗證。試試像這樣我希望這會有所幫助。

public class MyViewModel : INotifyPropertyChanged, IDataErrorInfo 
{ 
    public MyViewModel() 
    { 
     Value = 30; 
    } 
    private double _value; 

    [Range(1, 80, ErrorMessage = "out of range")] 
    public double Value 
    { 
     get 
     { 
      return _value; 
     } 
     set 
     { 
      _value = value; 
      ValidationMessageSetter("Value", value); 
     } 
    } 

    private void ValidationMessageSetter(string propertyName, object value) 
    { 
     Notify(propertyName); 
     string validationresult = ValidateProperty(propertyName, value); 
     if (!string.IsNullOrEmpty(validationresult) && !_dataErrors.ContainsKey(propertyName)) 
      _dataErrors.Add(propertyName, validationresult); 
     else if (_dataErrors.ContainsKey(propertyName)) 
       _dataErrors.Remove(propertyName); 

    } 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 

    private void Notify(string str) 
    { 
     if(PropertyChanged!=null) 
      PropertyChanged(this,new PropertyChangedEventArgs(str)); 
    } 

    private string ValidateProperty(string propertyName,object value) 
    { 
     var results = new List<ValidationResult>(2); 
     string error = string.Empty; 

     bool result = Validator.TryValidateProperty(
      value, 
      new ValidationContext(this, null, null) 
      { 
       MemberName = propertyName 
      }, 
      results); 

     if (!result && (value == null || ((value is int || value is long) && (int)value == 0) || (value is decimal && (decimal)value == 0))) 
      return null; 

     if (!result) 
     { 
      ValidationResult validationResult = results.First(); 
      error = validationResult.ErrorMessage; 
     } 

     return error;  
    } 

    #region IDataErrorInfo Members 

    private Dictionary<string, string> _dataErrors = new Dictionary<string, string>(); 

    public string Error 
    { 
     get { throw new NotImplementedException(); } 
    } 

    public string this[string columnName] 
    { 
     get 
     { 
      if (_dataErrors.ContainsKey(columnName)) 
       return _dataErrors[columnName]; 
      else 
       return null; 
     } 
    } 

    #endregion 
} 

<TextBox Text="{Binding Value, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/> 

我希望這會有所幫助。

+0

我簡化了代碼。現在我使用一種靈感來自您的文章的方法,這種方法在很多教程中都有介紹(但在我的程序中仍然失敗)。還有什麼提示? – Bastian 2012-07-26 13:02:24

+0

嗨,我已經更新了上面的答案。這工作正常,我希望這會幫助你提供一個想法。 – ethicallogics 2012-07-26 14:18:33

+0

感謝您採用這種方法。它幫助我開發了一種可行的解決方案(請參閱第一篇文章)。實際上它仍然可以使用依賴屬性。我這樣做有兩個原因:1.使用T4模板可以大大減少代碼量。 2.它應該更高性能,如[本文](http://www.codeproject.com/Articles/62158/DependencyProperties-or-INotifyPropertyChanged)中所述。 – Bastian 2012-08-28 08:52:45

0

IDataErrorInfo接口應該被綁定到,不具有該DependencyProperty物體上的物體上實現。

在您的例子,如果你想獲得驗證使用此機制那麼你的視圖模型需要爲Value財產做類似下面:

public class ViewModel : IDataErrorInfo 
{ 
    public string this[string columnName] 
    { 
     // Never gets called! 
     get 
     { 
      if (columnName == "Value") 
       return GetValidationMessageForValueField(); 

      return null; 
     } 
    } 
} 

我猜你真正想要做的是驗證有人在TextBox ..中輸入非數字值。如果是這種情況,您可能需要採取與使用不同的方法IDataErrorInfo

+0

嗯,我剛剛做了什麼,其他教程也做了(除了我的屬性實際上是一個依賴屬性)。例如。看看http://codeblitz.wordpress.com/2009/05/08/wpf-validation-made-easy-with-idataerrorinfo/ – Bastian 2012-07-26 13:37:31

+0

區別在於,在該教程中,「Customer」類是視圖模型。在你的例子中,你正在創建一個'Control'(當你從'TextBox'繼承) – 2012-07-26 13:42:20

+0

好吧,因爲我完全不知道視圖模型實際是什麼以及如何使用它,我會嘗試使用另一種方法:http ://www.codeproject.com/Articles/18678/Attaching-a-Virtual-Branch-to-the-Logical-Tree-in?msg = 4321473#xx4321473xx – Bastian 2012-07-26 14:27:08