2013-05-13 20 views
1

當WPF數據網格和驗證錯誤工具提示在驗證消息更改時沒有更新時,我有一個棘手的問題。這是與.Net 4代碼,所以我不能使用INotifyDataErrorInfo強制IDataErrorInfo.this [string columnName]被調用,以便更新驗證工具提示

我有一個ObservableCollection綁定到一個數據網格。該集合中的對象類型實現了IDataErrorInfo,以便我們可以支持驗證並突出顯示具有無效值的字段。這在大多數情況下工作正常。但是,也有是在以下情況下顯示在工具提示與消息相關的問題:

  1. 字段A有兩個規則規則1和規則S(共享規則)
  2. 字段B具有一個規則規則小號(共享規則)
  3. 規則S大於參考一共享規則既字段A和字段B
  4. 如果規則1和規則S分別都無效,我們得到示出的每個字段下面的驗證工具提示,這是我們想要的行爲:

    Field A < "Rule 1 is invalid. Rule S is invalid" 
    Field B < "Rule S is invalid" 
    
  5. 如果我們現在編輯字段B以使規則S有效。我們希望雙方的提示信息來更新如下:

    Field A < "Rule 1 is invalid." 
    Field B < (valid - no tooltip) 
    

注意,磁場A的有效化狀態沒有改變(Validation.HasError不改變的值),只有綁定到提示消息。

其實我們看到的是:

Field A < "Rule 1 is invalid. Rule S is invalid" 
Field B < (valid - no tooltip) 

NB底層ValidationError的類實例的數據是正確的,在這一點上。

看來UI不會更新字段A的工具提示文本,除非我們強制它重新查詢狀態並再次調用IDataErrorInfo.this [string columnName]。我發現迫使這種情況發生的唯一方法是手動引發字段A的屬性更改事件。但是,我不想這樣做,因爲字段A的值並未真正改變,只有綁定錯誤消息。雖然這個解決方案的作用是額外的和不必要的屬性改變事件與大量的數據性能發揮havok。

我能做些什麼來強制IDataErrorInfo.this [string columnName]被調用的字段B,而不必去提高屬性更改事件?

注意這裏是我們用來顯示驗證消息的錯誤數據模板。

<!-- ERROR HANDLING Data Template --> 
    <Style x:Key="controlBaseStyle" 
      TargetType="{x:Type Control}"> 

     <Setter Property="Validation.ErrorTemplate"> 
      <Setter.Value> 
       <ControlTemplate> 
        <Border BorderBrush="Red" 
          BorderThickness="2" 
          Visibility="{Binding ElementName=placeholder, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"> 
         <AdornedElementPlaceholder x:Name="placeholder"/> 
        </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 

     <Setter Property="ToolTipService.ShowOnDisabled" Value="true"/> 

     <Style.Triggers> 
      <Trigger Property="Validation.HasError" Value="true"> 
       <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem, Converter={StaticResource ErrorContentConverter}}"/> 
      </Trigger> 


      <!--We don't want to see the validation if the control is disabled. This doesn't affect it if the control is read only. --> 
      <Trigger Property="IsEnabled" Value="False"> 
       <Setter Property="Validation.ErrorTemplate"> 
        <Setter.Value> 
         <ControlTemplate> 
          <AdornedElementPlaceholder x:Name="placeholder"/> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
      </Trigger> 
     </Style.Triggers> 

    </Style> 

回答

0

你只需要提高PropertyChanged兩個屬性在每個setter,即:

  • 升起PropertyChangedAA setter和B
  • 升起PropertyChangedBA setter和B

這是我所知道的唯一途徑。

+0

這將工作,但似乎是一個非常暴力的解決方案(請參閱我的問題結束時的意見)。 A的值沒有改變,只有與A有關的錯誤信息。提升屬性改變了事件不必要地殺死了複雜場景中的性能,因爲太多的東西掛起了屬性改變的事件。我只是想讓框架再次調用IDataErrorInfo。如果沒有提高屬性更改事件,是否真的沒有辦法做到這一點? – 2013-05-13 16:06:09

+0

@MaxPalmer:如果我想知道另一種方式,我會發布它。你可以自由地等待其他答案:) – 2013-05-13 16:07:18

0

我通常會在我的對象中包含一個IsValid屬性,該屬性將通過驗證規則並返回true/false,如果該對象有效或無效。

通常我的代碼看起來像這樣。您的解決方案可能取決於你如何實現IDataErrorInfo

public class MyObject : ValidatingObject 
{ 
    public MyObject() 
    { 
     // Add Properties to Validate here 
     this.ValidatedProperties.Add("FieldA"); 
     this.ValidatedProperties.Add("FieldB"); 
    } 

    // Implement validation rules here 
    public override string GetValidationError(string propertyName) 
    { 
     if (ValidatedProperties.IndexOf(propertyName) < 0) 
     { 
      return null; 
     } 

     string s = null; 

     switch (propertyName) 
     { 
      case "FieldA": 
      case "FieldB": 
       if (FieldA <= FieldB) 
        s = "FieldA must be greater than FieldB"; 
       break; 
     } 

     return s; 
    } 

} 

而且通常實現IDataErrorInfoValidatingObject基類包含看起來不同以下幾點:

#region IDataErrorInfo & Validation Members 

/// <summary> 
/// List of Property Names that should be validated 
/// </summary> 
protected List<string> ValidatedProperties = new List<string>(); 

public abstract string GetValidationError(string propertyName); 

string IDataErrorInfo.Error { get { return null; } } 

string IDataErrorInfo.this[string propertyName] 
{ 
    get { return this.GetValidationError(propertyName); } 
} 

public bool IsValid 
{ 
    get 
    { 
     return (GetValidationError() == null); 
    } 
} 

public string GetValidationError() 
{ 
    string error = null; 

    if (ValidatedProperties != null) 
    { 
     foreach (string s in ValidatedProperties) 
     { 
      error = GetValidationError(s); 
      if (error != null) 
      { 
       return error; 
      } 
     } 
    } 

    return error; 
} 

#endregion // IDataErrorInfo & Validation Members 

然後你只需撥打IsValid每當你想要觸發驗證,如

if (SomeObject.IsValid) 
    CanSave = true; 

這對我來說也並不少見一個PropertyChange通知重新評估命令的CanSave()當一個屬性的變化,如

if (e.PropertyName == "FieldA" || e.PropertyName == "FieldB") 
    ((DelegateCommand)SaveCommand).RaiseCanExecuteChanged(); 

void CanSave() 
{ 
    return SomeObject.IsValid; 
} 

但與所有的說,如果你唯一的一次將被重新評估,如果字段是否有效是在另一個字段發生變化時,最好是Daniel saidFieldA發生更改時通知FieldB,並提出PropertyChange