用户控件内部控件的验证规则

3

编辑:我在这里找到了适合我的解决方案: http://social.msdn.microsoft.com/Forums/en/wpf/thread/c1fd21b2-424b-4536-be8c-335cee94596a

具体步骤如下:

    private void TextBoxLoaded(object sender, RoutedEventArgs e)
    {
        Binding bd = new Binding(TextBoxText.ToString());
        bd.ValidationRules.Add(new DataErrorValidationRule());
        bd.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        TextBox tb = sender as TextBox;
        tb.SetBinding(TextBox.TextProperty, bd);
    }

并且

<UserControl x:Class="WpfApplication1.UserControl1"
         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"
         xmlns:wa="clr-namespace:WpfApplication1"
         mc:Ignorable="d">
<DockPanel
    VerticalAlignment="Center">
    <Label
        VerticalAlignment="Center"
        Content="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type wa:UserControl1}},Path=LabelContent}"/>
    <TextBox
        VerticalAlignment="Center"
        MinWidth="96"
        Loaded="TextBoxLoaded">
    </TextBox>
</DockPanel>

and

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wa="clr-namespace:WpfApplication1"
    Title="MainWindow">
<Window.Resources>
    <DataTemplate x:Key="personDisplay">
        <DockPanel>
            <wa:UserControl1 LabelContent="First name:" TextBoxText="fname"/>
            <wa:UserControl1 LabelContent="Last name:" TextBoxText="lname"/>
            <wa:UserControl1 LabelContent="Age:" TextBoxText="age"/>
        </DockPanel>
    </DataTemplate>
</Window.Resources>
<ContentControl
    VerticalAlignment="Center"
    Name="personCcl"
    ContentTemplate="{StaticResource personDisplay}"/>

END

我有一个用户控件,需要包含标签和文本框,并且文本框中输入的条目需要具有验证规则,以检查输入的值是否有效。我有一个数据模板,使用用户控件显示具有多个字段的类。该类实现了IDataErrorInfo。然而,我的问题是文本框没有访问类的IDataErrorInfo,并且红色轮廓围绕无效控件,而不仅仅是在用户控件内部的文本框周围。

下面是我尝试做的简单示例。

以下是该类:

public class Person : IDataErrorInfo
{
    public string fname { get; set; }
    public string lname { get; set; }
    public int age { get; set; }

    public Person(string f, string l, int a)
    {
        fname = f;
        lname = l;
        age = a;
    }
    public string Error
    {
        get
        {
            if (age < 18) return "Too young";
            else if (fname == null || fname.Length == 0) return "Needs first name";
            else if (lname == null || lname.Length == 0) return "Needs last name";
            return null;
        }
    }
    public string this[string name]
    {
        get
        {
            if (name == "age") { return age < 18 ? "Too young" : null; }
            else if (name == "fname") { return fname == null || fname.Length == 0 ? "Needs first name" : null ; }
            else if (name == "lname") { return lname == null || lname.Length == 0 ? "Needs last name" : null; }
            return null;
        }
    }
}

以下是用户控件:

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }
    static readonly public DependencyProperty LabelContentProperty = DependencyProperty.Register(
        "LabelContent",
        typeof(string),
        typeof(UserControl1),
        new FrameworkPropertyMetadata("")
    );
    public string LabelContent
    {
        get { return GetValue(LabelContentProperty) as string; }
        set { SetValue(LabelContentProperty, value); }
    }
    static readonly public DependencyProperty TextBoxTextProperty = DependencyProperty.Register(
        "TextBoxText",
        typeof(object),
        typeof(UserControl1),
        new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnTextBoxTextChanged), new CoerceValueCallback(CoerceTextBoxText))
    );
    public object TextBoxText
    {
        get { return GetValue(TextBoxTextProperty); }
        set { SetValue(TextBoxTextProperty, value); }
    }
    static private void OnTextBoxTextChanged(DependencyObject dob, DependencyPropertyChangedEventArgs ea)
    {
        var uc = dob as UserControl1;
        uc.OnTextBoxTextChanged(new RoutedPropertyChangedEventArgs<object>(ea.OldValue, ea.NewValue, TextBoxTextChangedEvent));
    }
    static private object CoerceTextBoxText(DependencyObject dob, object o)
    {
        return o;
    }
    static readonly public RoutedEvent TextBoxTextChangedEvent = EventManager.RegisterRoutedEvent(
        "TextBoxTextChanged",
        RoutingStrategy.Bubble,
        typeof(RoutedPropertyChangedEventArgs<object>),
        typeof(UserControl1));
    public event RoutedPropertyChangedEventHandler<object> TextBoxTextChanged
    {
        add { AddHandler(TextBoxTextChangedEvent, value); }
        remove { RemoveHandler(TextBoxTextChangedEvent, value); }
    }
    protected virtual void OnTextBoxTextChanged(RoutedPropertyChangedEventArgs<object> ea) { RaiseEvent(ea); }
}

以下是用户控件的XAML代码:

<UserControl x:Class="WpfApplication1.UserControl1"
         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"
         xmlns:wa="clr-namespace:WpfApplication1"
         mc:Ignorable="d">
<DockPanel>
    <Label
        VerticalAlignment="Center"
        Content="{Binding RelativeSource={RelativeSource FindAncestor,
            AncestorType={x:Type wa:UserControl1}},
        Path=LabelContent}"/>
    <TextBox
        VerticalAlignment="Center"
        MinWidth="96">
        <TextBox.Text>
            <Binding 
                    RelativeSource="{RelativeSource FindAncestor,
                        AncestorType={x:Type wa:UserControl1}}"
                    Path="TextBoxText"
                    Mode="TwoWay"
                    UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <DataErrorValidationRule ValidatesOnTargetUpdated="True"/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
</DockPanel>

以下是Windows XAML(更新版):

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wa="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate x:Key="personDisplay">
        <DockPanel>
            <wa:UserControl1 LabelContent="First name:" TextBoxText="{Binding fname,Mode=TwoWay}"/>
            <wa:UserControl1 LabelContent="Last name:" TextBoxText="{Binding lname,Mode=TwoWay}"/>
            <wa:UserControl1 LabelContent="Age:" TextBoxText="{Binding age,Mode=TwoWay}"/>
        </DockPanel>
    </DataTemplate>
</Window.Resources>
<ContentControl
    VerticalAlignment="Center"
    Name="personCcl"
    ContentTemplate="{StaticResource personDisplay}"/>
</Window>

这是 Window 构造函数

    public MainWindow()
{
  InitializeComponent();
  personCcl.Content = new Person("John", "Smith", 33);
}

如果我错了,请纠正我。您想要为TextBox设置验证,并将其DataContext设置为ViewModel以触发验证吗?我不确定您在这里想要实现什么。 - 123 456 789 0
我对wpf还很陌生,所以无法正确表达所有术语。例如,在上面的代码中,如果我在保存年龄值的文本框中输入15,则应该转到person类并检查验证规则,并确定是“太年轻了”。但实际上并没有发生这种情况。似乎正在发生的是,文本框的绑定只是一个需要验证的字符串。我希望验证针对person类上的IDataErrorInfo进行,但仅适用于特定的文本框而不是整个用户控件。希望这有助于解释事情。 - uc71
你是否将ContentControl的DataContext设置为你的Person类? - 123 456 789 0
是的,抱歉,在MainWindow的构造函数中,我编辑了原帖。 - uc71
类似的问题和解决方案: http://stackoverflow.com/questions/29997315/binding-nested-validation-rules-on-nested-user-controls/32839858#32839858 - Reken411
1个回答

0

那是错的。不要让 personCc1.Content = new Person。而是让 personCc1.DataContext = new Person。Content 是期望你只显示该类的值,并且主要用于 UI。


好的,我有机会就试试。谢谢。 - uc71

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接