0

我非常精通 WPF,但对实现 UI 验证的领域很陌生,我需要确保某些值已准备好保存到数据库。在我非常大的应用程序中,我有很多不同类型的验证,其中包括简单的单个(TextBox 需要一个值或最少字符)、(必须选择项目)、(必须选择至少一个选项)等等。我已经使用 INotifyDataErrorInfo 实现了验证,并且效果非常好,除了一些我正在绕圈子并需要一些指导的问题。事实上,这可能更多的是样式问题。以下只是我的问题之一,但如果我解决了这个问题,那么它可能会解决其他问题,所以我现在会坚持这个:我有一组单选按钮控件,其中一个必须由用户选择,但我不希望默认选择任何一个,因此被迫做出选择。在他们选择一个之前,需要在堆栈面板中的单选按钮周围显示一个红色边框。因为这是我想在我有一组控件的几个地方做的事情,所以我认为创建一个名为 ErrorBorderControl 的边框控件会很好,它使用属性管理数据错误,然后将项目弹出到该控件中。我在这个名为 ValidationObject 的对象类型的控件上创建了一个 DependecyProperty,它只需要一个可以测试以查看是否有错误的属性。这完美地工作,并且在未选择时显示红色边框,而不是在选择时显示。到目前为止很棒。然而,ErrorBorderControl 中定义的 ControlTemplate 会渗入 UI 中所有其他基于边框的控件,包括 RadioButton 控件周围的边框。我经常使用样式并了解范围,但这很奇怪。以下是我所做的,虽然作为第一次尝试非常基本:

用户控制:

<UserControl 
  x:Class="Itec.Common.Wpf.CustomControls.Controls.ErrorBorderControl"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  mc:Ignorable="d">

  <!--
    Provides a border around grouped controls that needs error feedback  
  -->

  <Border>

    <!-- Style -->
    <Border.Style>
      <Style
        TargetType="{x:Type Border}"
        x:Name="TheTemplate">

        <!-- Error template definition -->
        <Setter Property="Validation.ErrorTemplate">
          <Setter.Value>
            <ControlTemplate>

              <!-- Adorner for the error visual -->
              <AdornedElementPlaceholder>

                <!-- Simple border around the control -->
                <Border 
                  BorderBrush="#ec7063" 
                  BorderThickness="1"/>

              </AdornedElementPlaceholder>

            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
    </Border.Style>
  </Border>
</UserControl>

代码背后:

/// <summary>
  /// Interaction logic for ErrorBorderControl.xaml
  /// </summary>
  public partial class ErrorBorderControl : UserControl
  {
    #region Dependency Properties

    /// <summary>
    /// The validation object property
    /// </summary>
    public static readonly DependencyProperty ValidationObjectProperty =
        DependencyProperty.Register("ValidationObject", typeof(object), typeof(ErrorBorderControl),
          new FrameworkPropertyMetadata(OnValidationObjectChanged));

    #endregion Dependency Properties

    #region Ctors

    /// <summary>
    /// Initializes a new instance of the <see cref="ErrorBorderControl"/> class.
    /// </summary>
    public ErrorBorderControl()
    {
      InitializeComponent();
    }

    #endregion Ctors

    #region Public Properties

    /// <summary>
    /// Gets or sets the validation object.
    /// </summary>
    /// <value>The validation object.</value>
    public object ValidationObject
    {
      get { return (object)GetValue(ValidationObjectProperty); }
      set { SetCurrentValue(ValidationObjectProperty, value); }
    }

    #endregion Public Properties

    #region Private Methods

    /// <summary>
    /// Raises when the ValidationObject property value changes
    /// </summary>
    /// <param name="d">The d.</param>
    /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
    private static void OnValidationObjectChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      ((ErrorBorderControl)d).ValidationObject = e.NewValue;
    }

    #endregion Private Methods
  }

执行:

<!-- Owner type -->
          <itc:ErrorBorderControl
            Grid.Row="1"
            ValidationObject="{Binding Path=RecordType, ValidatesOnNotifyDataErrors=True}">

            <StackPanel
              Orientation="Horizontal">

              <!-- Owner -->
              <itc:ItecRadioButton
                Content="{DynamicResource Language.SingleLine.Owner}"
                Margin="0,4,4,4"
                IsChecked="{Binding Path=RecordType, Converter={itc:EnumToBooleanConverter EnumValue={x:Static recordOwners:RecordOwnerRecordType.Owner}}}"/>

              <!-- FAO -->
              <itc:ItecRadioButton
                Content="{DynamicResource Language.SingleLine.FAO}"
                Margin="0,4,4,4"
                IsChecked="{Binding Path=RecordType, Converter={itc:EnumToBooleanConverter EnumValue={x:Static recordOwners:RecordOwnerRecordType.Fao}}}"/>

              <!-- Account Manager -->
              <itc:ItecRadioButton
                Content="{DynamicResource Language.SingleLine.Account_Manager}"
                Margin="0,4,4,4"
                IsChecked="{Binding Path=RecordType, Converter={itc:EnumToBooleanConverter EnumValue={x:Static recordOwners:RecordOwnerRecordType.AccountManager}}}"/>

              <!-- Watcher -->
              <itc:ItecRadioButton
                Content="{DynamicResource Language.SingleLine.Watcher}"
                Margin="0,4,4,4"
                IsChecked="{Binding Path=RecordType, Converter={itc:EnumToBooleanConverter EnumValue={x:Static recordOwners:RecordOwnerRecordType.Watcher}}}"/>

            </StackPanel>
          </itc:ErrorBorderControl>

输出:

无效选择

请注意,看起来模板虽然在用户控件中定义,但正在影响其他控件中的其他边框控件。看看我何时做出选择:

有效选择

红色的控件不参与验证。另一个控件中的控件模板如何影响所有边框?我只是不明白。我需要做的是定义一个模板,我可以将其应用于我希望它仅应用于的控件,并且能够重复使用它。

4

0 回答 0