我正在创建一个由动态创建的控件组成的窗口。我正在使用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(); }
}
错误'A'Binding'中的结果不能在'ValidationRuleCollection'集合中使用。 '绑定'只能在DependencyObject的DependencyProperty上设置。'。
我也遇到过IDataErrorInfo问题。无论我是在主视图模型中还是在描述符本身中实现它,我都无法获得要么调用的属性。我可能会遇到的问题是如何识别错误属性,因为我怀疑它总是“价值”,这是不明确的。事实上,这是大多数解决方案的问题,那些产生了我可以做出回应的事件让我没有任何工作环境。
这就是我当前的解决方案使用Tag属性的原因。没有它,很难将表单事件链接回底层业务对象。
答案 0 :(得分:1)
答案结果与我实现描述符类的方式(成为每个创建的框架元素的datacontext的对象)有关。我在&#39;错误的&#39;上实现了IDataErrorInfo。它所指的基类在类层次结构中是不可见的。经过一夜安眠后,我的眼睛很清醒,我几乎立刻就发现了它。
经常这样。