【发布时间】:2017-02-02 15:22:46
【问题描述】:
我正在创建一个由动态创建的控件组成的窗口。我正在使用 ItemsControl 创建它们:
<ItemsControl Grid.Row="0" Name="DynamicContent" ItemsSource="{Binding Path=EmbeddedInputControls}" ItemTemplateSelector="{Binding Path=EmbeddedInputControlsTemplateSelector}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
ItemTemplateSelector 根据资源类型选择DataTemplate:
<Window.Resources>
<converters:ErrorBooleanToBrush x:Key="ErrorBooleanToBrush"/>
<DataTemplate x:Key="EmbeddedStringInput" DataType="embeddedInputDescriptors:StringEmbeddedInputDescriptor">
<StackPanel Orientation="Horizontal" Background="{Binding IsErrored, Converter={StaticResource ErrorBooleanToBrush}}">
<Label Content="{Binding LabelContent}"></Label>
<dxe:TextEdit EditValue="{Binding TextValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsReadOnly}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="EmbeddedIntegerInput" DataType="embeddedInputDescriptors:IntegerEmbeddedInputDescriptor">
<StackPanel Orientation="Horizontal" Name="IntStackPanel">
<Label Content="{Binding LabelContent}"></Label>
<dxe:SpinEdit Value="{Binding IntValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsReadOnly}"
MinValue="{Binding MinValue}" MaxValue="{Binding MaxValue}" Validate="OnValidate" Tag="{Binding Self}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
这对于显示效果很好,但验证已被证明是一件令人头疼的事情。我终于找到的解决方案使用代码隐藏和OnValidate 事件处理程序:
private void OnValidate(object sender, ValidationEventArgs e)
{
var dynamicInputElement=((FrameworkElement)sender).Tag as IEmbeddedInputDescriptor;
var errorContent = dynamicInputElement?.ErrorContent(e.Value);
if(!string.IsNullOrEmpty(errorContent))
{
e.IsValid = false;
e.ErrorContent = errorContent;
}
}
这是我必须编写的唯一代码隐藏,我想摆脱它,但我无法看到没有它如何实现验证。验证规则将基于业务逻辑,因此我不能将它们包含在 XAML 中。当我给每个 DataTemplate 一个样式,其成员是从关联的描述符中获取的,但它有点难看时,我几乎得到了一个解决方案:
{Binding IsErrored, Converter={StaticResource ErrorBooleanToBrush}}
<StackPanel.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsErrored}" Value="True">
<Setter Property="StackPanel.Background" Value="LightCoral">
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
用于派生框架元素的对象是:
internal interface IEmbeddedInputDescriptor
{
bool IsReadOnly { get; }
bool IsRequired { get; }
object Value { get; }
bool IsErrored { get; }
string ErrorContent(object value);
}
摆脱代码隐藏会很好,我相信我会在这个过程中学到更多关于 WPF 的有用的东西。
更多信息:重新绑定验证:
<dxe:SpinEdit Value="{Binding IntValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidationRules={Binding valRules}}"
和
public IEnumerable<ValidationRule> valRules
{
get { throw new NotImplementedException(); }
}
导致错误“无法在“ValidationRuleCollection”集合中使用“绑定”。 “绑定”只能在 DependencyObject 的 DependencyProperty 上设置。'。
IDataErrorInfo 也有问题。无论我是在主视图模型中还是在描述符本身中实现它,我都没有设法调用任何一个属性。我应该做到这一点的一个可能问题是如何识别错误属性,因为我怀疑它总是“值”,这是模棱两可的。事实上,大多数解决方案都存在问题,那些产生了我可以响应的事件的解决方案让我没有工作的上下文。
这就是我当前的解决方案使用 Tag 属性的原因。否则,很难将表单事件链接回底层业务对象。
【问题讨论】:
-
我想您可能正在寻找
Binding.ValidationRules。您可以在DataTemplates 中进行设置。仍然有 C# 代码,但它以 MVVMish 的方式被考虑在内。您还可以查看IDataErrorInfo,它将验证放在视图模型中。 -
"I broke the example code!" 好的。 “而且现在不行了!”是的,这是通常的结果。还有什么可以帮助你的吗?
-
嗯?你现在有什么建议?比起阅读无意义的帖子,我还有更好的事情要做。
-
我在 MSDN 上链接了示例代码。您发布了一些奇怪的 ValidationRules 代码,这些代码不可能工作,而且示例中肯定没有。我什至不明白你对
IDataErrorInfo的反对;没有一个类有不止一个名为Value(或其他任何东西)的属性。无论如何,没有人可以在没有看到代码的情况下帮助您。 -
我正在使用几个基类,底部的基类确实有一个“值”属性。因此,在尝试识别已修改的内容时,被告知“价值”已更改是模棱两可的。
标签: c# wpf validation