我有一个ViewModel,它代表多个选项并实现IDataErrorInfo
。此ViewModel仅在选择了至少其中一个选项时才有效。它绑定到ContentControl
。 DataTemplate
用于将ViewModel可视化为包含GroupBox
的{{1}}。另一个ItemsControl
将每个选项可视化为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>
答案 0 :(得分:3)
要使ContentControl与之一起工作,我该怎么做 IDataErrorInfo并在选中复选框时检查其有效性 未检查?
向 Rachels 答案添加一点。
使用异步数据验证更容易解决此问题,但遗憾的是,WPF 4.5 is released之前无法使用此问题。
Content
与GeneralInvoiceTypes
中的MainViewModel
绑定。由于我们无法进行异步数据验证,因此必须为PropertyChanged
引发GeneralInvoiceTypes
才能进行验证。这可行,但我会采用 Rachel 建议的方法,并在 MultipleOptionsViewModel
IsValid
的属性
IsValid
的绑定可以从Tag
(或附加属性)到GeneralInvoiceTypes.IsValid
完成。在任何IsChecked
中更改Options
时,我们还必须在 MultipleOptionsViewModel 中收到通知。这可以通过在CheckBoxes
中使用命令绑定来完成。
因此需要对以下几行进行一些更改。
我还上传了一个示例项目,其实现方式如下: https://www.dropbox.com/s/fn8e4n4s68wj3vk/ContentControlValidationTest.zip?dl=0
ContentControl中
<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;
}
}
答案 1 :(得分:1)
包含GeneralInvoiceTypes
属性的类是否实现IDataErrorInfo
?
设置ValidatesOnDataErrors=True
将显示包含绑定属性的DataContext的验证错误,因此在这种情况下它是validing ParentViewModel.GetValidationError("GeneralInvoiceTypes")
,而不是GeneralInvoiceTypes.GetValidationError()
在这种情况下,您可以将IDataErrorInfo
添加到ParentViewModel
并通过返回验证错误来验证GeneralInvoiceTypes
属性,如下所示:
public string GetValidationError(string propertyName)
{
if (propertyName == "GeneralInvoiceTypes")
return GeneralInvoiceTypes.GetValidationError();
return null;
}
或者您可以在IsValid
上创建一个GeneralInvoiceTypes
属性,该属性返回GetValidationError() == null
并将验证触发器设置为{Binding IsValid}
,而不是Validation.HasError
答案 2 :(得分:0)
根据给出的答案,我解决了这个问题:
更改DataTemplate
的{{1}},将MultipleOptionsViewModel
属性与Options
绑定:
ValidatesOnDataErrors=True
将错误样式更改为定位<DataTemplate DataType="{x:Type ViewModels:MultipleOptionsViewModel}">
<GroupBox Header="{Binding Title}">
<ItemsControl ItemsSource="{Binding Options,
ValidatesOnDataErrors=True}"/>
</GroupBox>
</DataTemplate>
而不是ItemsControl
。
ContentControl
为MultipleOptionsViewModel
引发PropertyChanged "Options"
MultipleOptionsViewModel
在其实施中对IDataErrorInfo.Item
的列"Options"
作出反应,即在其索引器中。此解决方案具有以下优点:它使用IDataErrorInfo
的默认行为,即此ViewModel的使用者不需要任何特殊处理。
我知道这个解决方案与我在问题中提到的问题不完全相同 - 错误模板现在显示在里面组合框而不是它周围,但这是我能活的东西用。