支持IDataErrorInfo由内容绑定到ContentControl实现
本文关键字:ContentControl 实现 绑定 IDataErrorInfo 支持 | 更新日期: 2023-09-27 18:12:18
我有一个表示多个选项并实现IDataErrorInfo
的ViewModel。这个ViewModel只有在这些选项中至少有一个被选中时才有效。它连着一个ContentControl
。DataTemplate
用于将ViewModel可视化为包含ItemsControl
的GroupBox
。另一个DataTemplate
将每个选项可视化为CheckBox
。
我要做什么,使ContentControl
与IDataErrorInfo
一起工作,并在复选框被选中或未选中时检查有效性?
一些代码:绑定:
<ContentControl Content="{Binding GeneralInvoiceTypes, ValidatesOnDataErrors=True}"
Margin="0,0,5,0" />
数据模板:<DataTemplate DataType="{x:Type ViewModels:MultipleOptionsViewModel}">
<GroupBox Header="{Binding Title}">
<ItemsControl ItemsSource="{Binding Options}" />
</GroupBox>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:OptionViewModel}">
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Name}"
Margin="6,3,3,0" />
</DataTemplate>
风格:
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<Trigger Property="Validation.HasError"
Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Border BorderBrush="Red"
BorderThickness="1"
CornerRadius="2.75"
Grid.Column="0">
<AdornedElementPlaceholder Grid.Column="0" />
</Border>
<TextBlock Foreground="Red"
Grid.Column="1"
Margin="0"
FontSize="12"
VerticalAlignment="Center"
HorizontalAlignment="Left"
x:Name="txtError">
*
</TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我要做什么,使ContentControl与IDataErrorInfo,并在选中或选中复选框时检查有效性未经检查的吗?
在 rachel 的答案中添加了一点。
这个问题可以更容易地通过异步数据验证来解决,但不幸的是,在WPF 4.5发布之前,这是不可用的。
Content
与MainViewModel
中的GeneralInvoiceTypes
绑定。由于我们不能进行异步数据验证,因此必须为GeneralInvoiceTypes
引发PropertyChanged
以进行验证。这是可行的,但我会采用Rachel建议的方法并在MultipleOptionsViewModel
IsValid
的属性到IsValid
的绑定可以从Tag
(或附加属性)到GeneralInvoiceTypes.IsValid
。当IsChecked
在任何Options
中改变时,我们也必须在MultipleOptionsViewModel中得到通知。这可以通过在CheckBoxes
中使用命令绑定来完成,例如。
因此需要对以下行进行一些更改。
我还上传了一个示例项目,在这里实现: https://www.dropbox.com/s/fn8e4n4s68wj3vk/ContentControlValidationTest.zip?dl=0
继承自ContentControl <<p> /em><ContentControl Content="{Binding Path=GeneralInvoiceTypes}"
Tag="{Binding Path=GeneralInvoiceTypes.IsValid,
ValidatesOnDataErrors=True}" />
OptionViewModel DataTemplate
<DataTemplate DataType="{x:Type ViewModels:OptionViewModel}">
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Name}"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContentControl}},
Path=DataContext.IsValidCheckCommand}"
Margin="6,3,3,0" />
</DataTemplate>
MultipleOptionsViewModel
private ICommand m_isValidCheckCommand;
public ICommand IsValidCheckCommand
{
get
{
return m_isValidCheckCommand ??
(m_isValidCheckCommand = new RelayCommand(param => IsValidCheck()));
}
}
private void IsValidCheck()
{
IsValid = CheckIsValid();
}
private bool CheckIsValid()
{
foreach (OptionViewModel option in Options)
{
if (option.IsChecked == true)
{
return true;
}
}
return false;
}
private bool m_isValid;
public bool IsValid
{
get { return m_isValid; }
set
{
m_isValid = value;
OnPropertyChanged("IsValid");
}
}
public string this[string columnName]
{
get
{
if (columnName == "IsValid")
{
if (IsValid == false)
{
return "At least 1 Option must be selected";
}
}
return string.Empty;
}
}
包含GeneralInvoiceTypes
属性的类是否实现了IDataErrorInfo
?
设置ValidatesOnDataErrors=True
将显示包含绑定属性的DataContext的验证错误,因此在本例中它验证的是ParentViewModel.GetValidationError("GeneralInvoiceTypes")
,而不是GeneralInvoiceTypes.GetValidationError()
在这种情况下,您可以将IDataErrorInfo
添加到ParentViewModel
中,并通过返回验证错误来验证GeneralInvoiceTypes
属性,像这样:
public string GetValidationError(string propertyName)
{
if (propertyName == "GeneralInvoiceTypes")
return GeneralInvoiceTypes.GetValidationError();
return null;
}
或者你可以在GeneralInvoiceTypes
上创建一个IsValid
属性,它返回GetValidationError() == null
,并基于{Binding IsValid}
而不是Validation.HasError
的验证触发器
根据给出的答案,我是这样解决的:
-
更改
MultipleOptionsViewModel
的DataTemplate
,将Options
属性与ValidatesOnDataErrors=True
绑定:<DataTemplate DataType="{x:Type ViewModels:MultipleOptionsViewModel}"> <GroupBox Header="{Binding Title}"> <ItemsControl ItemsSource="{Binding Options, ValidatesOnDataErrors=True}"/> </GroupBox> </DataTemplate>
-
将错误样式从
ContentControl
改为ItemsControl
- 确保当一个子选项被选中或未选中时,
MultipleOptionsViewModel
引发"Options"
的PropertyChanged - 确保
MultipleOptionsViewModel
在IDataErrorInfo.Item
的实现中响应"Options"
列,即在其索引器中。
这个解决方案的好处是,它使用了IDataErrorInfo
的默认行为,也就是说,这个ViewModel的消费者不需要处理它任何特殊的。
我知道这个解决方案不是100%等同于我在问题中所问的-错误模板现在显示在组框内,而不是在它周围,但这是我可以忍受的。