2011-08-19 59 views
17

我有兩個日期字段:StartDate和EndDate。 StartDate必須早於EndDate。如何在其中任何一個屬性發生更改時驗證多個屬性?

如果用戶將StartDate更改爲比EndDate更大的值,則該DatePicker周圍將出現紅色邊框,反之亦然。如果用戶更改第二個框以便日期範圍現在正確,則第一個框仍然存在驗證錯誤。

如何驗證兩個日期字段,當其中任何一個更改?

enter image description here

我使用IDataErrorInfo

public string GetValidationError(string propertyName) 
{ 
    switch (propertyName) 
    { 
     case "StartDate": 
      if (StartDate > EndDate) 
       s = "Start Date cannot be later than End Date"; 
      break; 

     case "EndDate": 
      if (StartDate > EndDate) 
       s = "End Date cannot be earlier than Start Date"; 
      break; 
    } 

    return s; 
} 

我不能簡單地提出一個PropertyChange事件,因爲我需要驗證這兩個字段時其中一方的變化,所以有他們兩人提出一個PropertyChange事件對方會陷入無限循環。

如果其他日期返回驗證錯誤,我也不喜歡清除日期字段的想法。

+0

只是要拋出一種替代方法,當兩個規則被打破時,你能否把兩個盒子都變成紅色?如果是這樣,你只需要提出一個propertychanged事件。 – Josh

+0

@Josh很想去,但我不知道如何手動提高各個屬性的驗證事件 – Rachel

+0

我退出了使用驗證事件。我認爲他們應該開火,而他們沒有或他們開火,邊界不突出,我對他們的問題太多了。我使用綁定到有效的布爾表示的紅色邊框樣式。我也將工具提示綁定到消息屬性。然後,當一個值改變我驗證它並適當地設置屬性。 – Josh

回答

14

最簡單的方法是在二傳手提出一個PropertyChanged通知爲需要像bathineni suggests

private DateTime StartDate 
{ 
    get { return _startDate; } 
    set 
    { 
     if (_startDate != value) 
     { 
      _startDate = value; 
      RaisePropertyChanged("StartDate"); 
      RaisePropertyChanged("EndDate"); 
     } 
    } 
} 

private DateTime EndDate 
{ 
    get { return _endDate; } 
    set 
    { 
     if (_endDate!= value) 
     { 
      _endDate= value; 
      RaisePropertyChanged("StartDate"); 
      RaisePropertyChanged("EndDate"); 
     } 
    } 
} 

但是要驗證這兩個屬性,如果不適合你,我想出了一個辦法,驗證一組屬性在一起,雖然你的類除了擁有INotifyPropertyChanged實施INotifyPropertyChanging(我用的EntityFramework,默認情況下其類實現兩個接口)

擴展方法

public static class ValidationGroup 
{ 
    public delegate string ValidationDelegate(string propertyName); 
    public delegate void PropertyChangedDelegate(string propertyName); 

    public static void AddValidationGroup<T>(this T obj, 
     List<string> validationGroup, bool validationFlag, 
     ValidationDelegate validationDelegate, 
     PropertyChangedDelegate propertyChangedDelegate) 
     where T : INotifyPropertyChanged, INotifyPropertyChanging 
    { 

     // This delegate runs before a PropertyChanged event. If the property 
     // being changed exists within the Validation Group, check for validation 
     // errors on the other fields in the group. If there is an error with one 
     // of them, set a flag to true. 
     obj.PropertyChanging += delegate(object sender, PropertyChangingEventArgs e) 
     { 
      if (validationGroup.Contains(e.PropertyName)) 
      { 
       foreach(var property in validationGroup) 
       { 
        if (validationDelegate(property) != null) 
        { 
         validationFlag = true; 
         break; 
        } 
       } 
      } 
     }; 

     // After the Property gets changed, if another field in this group was 
     // invalid prior to the change, then raise the PropertyChanged event for 
     // all other fields in the Validation Group to update them. 
     // Also turn flag off so it doesn't get stuck in an infinite loop 
     obj.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e) 
     { 
      if (validationGroup.Contains(e.PropertyName)) 
      { 
       if (validationFlag && validationDelegate(e.PropertyName) == null) 
       { 
        validationFlag = false; 
        foreach(var property in validationGroup) 
        { 
         propertyChangedDelegate(property); 
        } 
       } 
      } 
     }; 
    } 
} 

要使用它,請將以下調用添加到應該驗證一組屬性的任何類的構造函數中。

this.AddValidationGroup(
    new List<string> { "StartDate", "EndDate" }, 
    GetValidationError, OnPropertyChanged); 

我已經在一個驗證組中測試了多達3個屬性,它似乎工作正常。

+0

我和你有完全相同的問題。您是否使用INotifyPropertyChanging解決方案,或者您是否找到其他方法? –

+0

@Björn在這種情況下,我使用了'INotifyPropertyChanging',因爲接口已經由實體框架實現。如果沒有,我可能會在相關屬性 – Rachel

+0

的'set'方法中引發我的PropertyChanged事件。感謝您的信息。我刪除了我的驗證並更改了我的代碼,這樣如果StartDate> EndDate我簡單地設置EndDate = StartDate。也許不是每個人都可以做的事情,但它適合我的情況。 –

0

我通常會將所有驗證錯誤添加到字典中,並通過屬性名稱使驗證模板訂閱該驗證模板。在每個屬性更改的事件處理程序中,我可以檢查任意數量的屬性,並根據需要添加或刪除其驗證狀態。

查看this answer瞭解我的實施情況。對不起,它在VB.NET中,但應該相當簡單。

2

用這一招,它可以防止他們稱OnPropertyChanged對方:

private bool RPCfromStartDate = false; 
private bool RPCfromEndDate = false; 

public string this[string columnName] 
{ 
    get 
    { 
       string result = null; 
       switch (columnName) 
       { 
        case "StartDate": 
         if (StartDate.Date >= EndDate.Date) 
         { 
          result = "Start Date cannot be later than End Date"; 
         } 
         if (!RPCfromEndDate) 
         { 
          RPCfromStartDate = true;        
          OnPropertyChanged("EndDate"); 
          RPCfromStartDate = false; 
         } 
        case "EndDate": 
         if (StartDate.Date >= EndDate.Date) 
         { 
          result = "End Date cannot be earlier than Start Date"; 
         } 
         if (!RPCfromStartDate) 
         { 
          RPCfromEndDate = true;        
          OnPropertyChanged("StartDate"); 
          RPCfromEndDate = false; 
         } 
         break; 
       } 
... 
-1

您也可以訂閱到需要綁定SelectedDateChanged事件處理程序和更新。

+0

正如我在我的問題中所說,這不起作用,因爲我有兩個日期,所以它會卡住在一個無限循環。 – Rachel

+0

我不確定什麼讓你感到困惑。當startDate改變時,你更新EndDate綁定(只是驗證發生,沒有改變)。當endDate更改時,您更新StartDate綁定。沒有無限循環應該發生。 –

相關問題