设置 UserControl 的特定子项的错误模板

Posted

技术标签:

【中文标题】设置 UserControl 的特定子项的错误模板【英文标题】:Set error template of a specific child of a UserControl 【发布时间】:2022-01-13 00:42:08 【问题描述】:

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

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

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

另外,这个想法是验证应该在模型类中完成,所以我不想在UserControl 中放置任何验证机制。

在这种情况下,我真的不明白绑定系统是如何工作的。整个UserControl 在错误中突出显示是有道理的,因为它是绑定到Model 属性的UserControl 属性,但我希望能够将错误“重定向”到Validation.ValidationAdornerSite 的孩子。我错过了什么或误解了什么?例如,如何突出显示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;
    

【问题讨论】:

【参考方案1】:

您可以使用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>

【讨论】:

解决了这个问题。但是你知道为什么在 UserControl 上使用Validation.ValidationAdornerSite 不起作用吗?因为文档的备注部分说“Validation.ValidationAdornerSite 和 Validation.ValidationAdornerSiteFor 附加属性相互引用,您可以设置任何一个。”。 @RodolfoRibeiro 因为这将无法解决后代的名称并导致绑定错误。

以上是关于设置 UserControl 的特定子项的错误模板的主要内容,如果未能解决你的问题,请参考以下文章

不支持在 UserControl 上设置 Template 属性

属于 UserControl 子级的错误与 UserControl 而不是子级相关联

将子级添加到 UserControl

UserControl 中经过验证的文本框

绑定ListBox中Usercontrol的DependencyProperty

具有属性绑定的自定义 UserControl 模板