验证WPF动态创建的框架元素

时间:2017-02-02 15:22:47

标签: c# wpf validation

我正在创建一个由动态创建的控件组成的窗口。我正在使用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属性的原因。没有它,很难将表单事件链接回底层业务对象。

1 个答案:

答案 0 :(得分:1)

答案结果与我实现描述符类的方式(成为每个创建的框架元素的datacontext的对象)有关。我在&#39;错误的&#39;上实现了IDataErrorInfo。它所指的基类在类层次结构中是不可见的。经过一夜安眠后,我的眼睛很清醒,我几乎立刻就发现了它。

经常这样。