设置 UserControl 的特定 child 的错误模板

Set error template of a specific child of a UserControl

我正在尝试了解如何将错误模板添加到 UserControl 的 child,并且我看到了其他类似的问题,但我仍然无法解决这个问题。

我的目标是创建一个 UserControl,其中包含一个 TextBox 和一个 Label,以及一个可选的只读 TextBox。我已经实现了很多功能并且一切正常,除了整个 UserControl 在验证错误的情况下会出现红色边框。

我尝试将 Validation.ValidationAdornerSite 添加到 UserControl 的根元素,但没有成功。

此外,想法是验证应该在模型 类 内部完成,所以我不想在 UserControl.

内部放置任何验证机制

在这种情况下,我不太了解绑定系统的工作原理。整个 UserControl 在错误上突出显示是有道理的,因为它是 UserControl 的 属性 绑定到 Model 的 属性,但我希望能够将错误“重定向”到带有 Validation.ValidationAdornerSite 的 child。我错过了什么或误解了什么?例如,如何突出显示 TextBox "txt1"?

提前致谢!

这是我能想到的最小示例:

MyControl.xaml

<UserControl x:Class="MyNamespace.MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel x:Name="ctRoot">
        <Label x:Name="lbTitle" Content="MyLabel"/>
        <TextBox x:Name="txt1" Text="{Binding Text}"/>
        <TextBox x:Name="txt2"/>
    </StackPanel>
</UserControl>

MyControl.xaml.cs

public partial class MyControl : UserControl
{
    public MyControl()
    {
        InitializeComponent();
        ctRoot.DataContext = this;
    }

    public static readonly DependencyProperty TextProperty = DependencyProperty
        .Register("Text", typeof(string), typeof(MyControl), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
        
    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
}

Model.cs

public class Model : INotifyDataErrorInfo, INotifyPropertyChanged
{
    private string m_prop;
    public string MyProp
    {
        get => m_prop;

        set
        {
            m_errors.Clear();
            ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(MyProp)));

            if (value.Length == 0)
            {
                m_errors.Add("Cannot be empty");
                ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(MyProp)));
            }

            m_prop = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyProp)));
        }
    }

    private List<string> m_errors = new List<string>();
    public bool HasErrors => m_errors.Count > 0;
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    public event PropertyChangedEventHandler PropertyChanged;

    public IEnumerable GetErrors(string propertyName)
    {
        return m_errors;
    }
}

MyWindow.xaml

<Window x:Class="MyNamespace.MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyNamespace"
        Title="MyWindow" Width="200" Height="200">
    <StackPanel>
        <local:MyControl Text="{Binding MyProp}" Margin="10"/>
    </StackPanel>
</Window>

MyWindow.xaml.cs

public partial class MyWindow : Window
{
    public Model model = new Model();

    public MyWindow()
    {
        InitializeComponent();
        DataContext = model;
    }
}

您可以使用 Validation.ValidationAdornerSiteFor 更改显示哪个元素以指示发生错误。

<UserControl x:Class="WpfApp1.MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Name="myControl">
    <StackPanel x:Name="ctRoot">
        <Label x:Name="lbTitle" Content="MyLabel"/>
        <TextBox x:Name="txt1" Text="{Binding Text, ElementName=myControl}"
                 Validation.ValidationAdornerSiteFor="{Binding ElementName=myControl}"/>
        <TextBox x:Name="txt2"/>
    </StackPanel>
</UserControl>