INotifyDataErrorInfo ErrorsChanged 不适用于绑定到 ListCollectionView 的 UI 元素
INotifyDataErrorInfo ErrorsChanged doesn't work for UI element bound to a ListCollectionView
此 XAML 元素绑定到我的视图模型中的 ListCollectionView:
<Style x:Key="ErrorStyle" TargetType="{x:Type Control}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="Background" Value="Salmon"/>
</Trigger>
</Style.Triggers>
</Style>
...
<controls:AutoCompleteBox Grid.Column="1" Grid.Row="0" Margin="5" Height="20" Width="270" HorizontalAlignment="Left" VerticalAlignment="Center"
Name="typeName"
Style="{StaticResource ErrorStyle}"
Text="{Binding Path=AirframeCollectionView/TypeName, UpdateSourceTrigger=LostFocus, Mode=TwoWay,
ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True,
ValidatesOnExceptions=True}"
ItemsSource="{Binding Path=TypeNames}"
IsTextCompletionEnabled="True"
FilterMode="Contains"
MinimumPrefixLength="3">
</controls:AutoCompleteBox>
ListCollectionView 的定义如下:
public ListCollectionView AirframeCollectionView
{
get
{
return this.airframeCollectionView;
}
set
{
this.airframeCollectionView = value;
this.RaisePropertyChanged("AirframeCollectionView");
}
}
并初始化:
this.currentAirframes = new ObservableCollection<Airframe>(this.UnitOfWork.Airframes.GetAirframesForRegistration(this.SearchRegistration));
this.AirframeCollectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.currentAirframes);
验证时 AirframeCollectionView/TypeName 我正在使用 INotifyDataErrorInfo 接口,因此:
private readonly Dictionary<string, ICollection<string>> validationErrors = new Dictionary<string, ICollection<string>>();
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public bool HasErrors
{
get { return this.validationErrors.Count > 0; }
}
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName) || !this.validationErrors.ContainsKey(propertyName))
{
return null;
}
return this.validationErrors[propertyName];
}
private void RaiseErrorsChanged(string propertyName)
{
if (this.ErrorsChanged != null)
{
this.ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
为了引发错误,我一直在这样做:
this.validationErrors["AirframeCollectionView/TypeName"] = validationErrors;
this.RaiseErrorsChanged("AirframeCollectionView/TypeName");
然而,这不会触发 UI 中的错误响应。我将 属性 名称从 "AirframeCollectionView/TypeName" 更改为 "TypeName",但这也不起作用。在调试器中,我已经确认 validationErrors 加载了错误,并且 ErrorsChanged 被提供的 属性 名称触发。
请注意,当我在模型而不是 ViewModel 中实现 INotifyDataErrorInfo 时,这一切都有效,但出于各种原因,我希望在 ViewModel 中实现。
问题
在设置 DataErrorsChangedEventArgs 和触发 ErrorsChanged 时,我必须使用什么 属性 名称格式?还是我这里有其他结构性问题?
我得出结论,当在视图模型中使用 ListCollectionView 属性 并从视图模型中触发 ErrorsChanged 时,您无法让 INotifyDataErrorInfo 与 UI 对话。因此,为了使它正常工作,我有:
- 在模型中 (POCO) - 实现了 INotifyDataError。包括 public RaiseErrorsChanged 方法,它允许传入 属性 名称和错误列表。这会将错误添加到错误字典中,然后触发 ErrorsChanged。
- 在视图模型中 - 订阅了 ListCollectionView 中每个 Airframe 对象的 PropertyChanged 事件。在 PropertyChanged 事件处理程序中,我执行验证,然后使用任何错误详细信息调用机身的 RaiseErrorsChanged 方法。
这将定制验证排除在模型之外,一切都很好。
此 XAML 元素绑定到我的视图模型中的 ListCollectionView:
<Style x:Key="ErrorStyle" TargetType="{x:Type Control}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="Background" Value="Salmon"/>
</Trigger>
</Style.Triggers>
</Style>
...
<controls:AutoCompleteBox Grid.Column="1" Grid.Row="0" Margin="5" Height="20" Width="270" HorizontalAlignment="Left" VerticalAlignment="Center"
Name="typeName"
Style="{StaticResource ErrorStyle}"
Text="{Binding Path=AirframeCollectionView/TypeName, UpdateSourceTrigger=LostFocus, Mode=TwoWay,
ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True,
ValidatesOnExceptions=True}"
ItemsSource="{Binding Path=TypeNames}"
IsTextCompletionEnabled="True"
FilterMode="Contains"
MinimumPrefixLength="3">
</controls:AutoCompleteBox>
ListCollectionView 的定义如下:
public ListCollectionView AirframeCollectionView
{
get
{
return this.airframeCollectionView;
}
set
{
this.airframeCollectionView = value;
this.RaisePropertyChanged("AirframeCollectionView");
}
}
并初始化:
this.currentAirframes = new ObservableCollection<Airframe>(this.UnitOfWork.Airframes.GetAirframesForRegistration(this.SearchRegistration));
this.AirframeCollectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.currentAirframes);
验证时 AirframeCollectionView/TypeName 我正在使用 INotifyDataErrorInfo 接口,因此:
private readonly Dictionary<string, ICollection<string>> validationErrors = new Dictionary<string, ICollection<string>>();
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public bool HasErrors
{
get { return this.validationErrors.Count > 0; }
}
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName) || !this.validationErrors.ContainsKey(propertyName))
{
return null;
}
return this.validationErrors[propertyName];
}
private void RaiseErrorsChanged(string propertyName)
{
if (this.ErrorsChanged != null)
{
this.ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
为了引发错误,我一直在这样做:
this.validationErrors["AirframeCollectionView/TypeName"] = validationErrors;
this.RaiseErrorsChanged("AirframeCollectionView/TypeName");
然而,这不会触发 UI 中的错误响应。我将 属性 名称从 "AirframeCollectionView/TypeName" 更改为 "TypeName",但这也不起作用。在调试器中,我已经确认 validationErrors 加载了错误,并且 ErrorsChanged 被提供的 属性 名称触发。
请注意,当我在模型而不是 ViewModel 中实现 INotifyDataErrorInfo 时,这一切都有效,但出于各种原因,我希望在 ViewModel 中实现。
问题
在设置 DataErrorsChangedEventArgs 和触发 ErrorsChanged 时,我必须使用什么 属性 名称格式?还是我这里有其他结构性问题?
我得出结论,当在视图模型中使用 ListCollectionView 属性 并从视图模型中触发 ErrorsChanged 时,您无法让 INotifyDataErrorInfo 与 UI 对话。因此,为了使它正常工作,我有:
- 在模型中 (POCO) - 实现了 INotifyDataError。包括 public RaiseErrorsChanged 方法,它允许传入 属性 名称和错误列表。这会将错误添加到错误字典中,然后触发 ErrorsChanged。
- 在视图模型中 - 订阅了 ListCollectionView 中每个 Airframe 对象的 PropertyChanged 事件。在 PropertyChanged 事件处理程序中,我执行验证,然后使用任何错误详细信息调用机身的 RaiseErrorsChanged 方法。
这将定制验证排除在模型之外,一切都很好。