我非常精通WPF,但对实现UI验证的领域很陌生,我需要确保某些值已准备好保存到数据库。在我非常大的应用程序中,我有很多不同类型的验证,其中包括简单的单一(TextBox需要一个值或最小字符),(必须选择项目),(必须至少选择一个选项),依此类推。 我已经使用INotifyDataErrorInfo实现了验证,这非常有效,除了一些问题,我正在圈子里并需要一些指导。事实上,这可能更多是造型问题。以下只是我的一个问题,但如果我解决这个问题,那么它可以解决其他问题,所以我现在就坚持这个: 我有一组单选按钮控件,其中一个必须由用户选择,但我不希望任何选择默认,因此被迫做出选择。在他们选择一个之前,需要在堆叠面板中的单选按钮周围显示红色边框。因为这是我想在我有一组控件的几个地方做的事情,我认为最好创建一个名为ErrorBorderControl的Border控件,它使用属性管理数据错误,然后将项目弹出到此控件中。我在这个名为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>
输出:
请注意,虽然模板虽然在用户控件中定义,但它正在影响其他控件中的其他Border控件。看看我做出选择的时间:
以红色表示的控件不参与验证。另一个控件中的控件模板如何影响所有边框?我只是不明白。我需要做的是定义一个模板,我可以将其应用于我希望仅应用于控件的控件,并且能够重复使用它。