Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将验证错误传递给可重用UserControl中的子控件_C#_Wpf_Validation_Data Binding_Wpf Controls - Fatal编程技术网

C# 如何将验证错误传递给可重用UserControl中的子控件

C# 如何将验证错误传递给可重用UserControl中的子控件,c#,wpf,validation,data-binding,wpf-controls,C#,Wpf,Validation,Data Binding,Wpf Controls,我创建了自己的UserControl,名为PersonNameControl,打算重用。 该控件有三个TextBox字段,并且在其类文件中有三个依赖属性 名字 插入 姓氏 每个依赖项属性值都绑定到一个字段,因此依赖项属性Firstname绑定到FirstnameTextBox,依此类推 我没有明确地设置UserControl的DataContext。 控件应尽可能松散。它应该只通过依赖属性获取它的值(字段)。它甚至不应该寻找类似DataContext的东西 名字: 插入: 姓氏: 和控制

我创建了自己的
UserControl
,名为
PersonNameControl
,打算重用。 该控件有三个
TextBox
字段,并且在其类文件中有三个依赖属性

  • 名字
  • 插入
  • 姓氏
每个依赖项属性值都绑定到一个字段,因此依赖项属性Firstname绑定到Firstname
TextBox
,依此类推

我没有明确地设置UserControl的DataContext。 控件应尽可能松散。它应该只通过依赖属性获取它的值(字段)。它甚至不应该寻找类似DataContext的东西


名字:
插入:
姓氏:
和控制类:

公共部分类PersonNameControl:UserControl
{
公共PersonNameControl()
{
初始化组件();
}
公共字符串名
{
获取{return(string)GetValue(FirstnameProperty);}
set{SetValue(FirstnameProperty,value);}
}
公共静态只读DependencyProperty FirstnameProperty=
DependencyProperty.Register(“Firstname”、typeof(string)、typeof(PersonNameControl),
新的FrameworkPropertyMetadata(“,FrameworkPropertyMetadataOptions.bindstwoway默认值));
公共字符串插入
{
获取{return(string)GetValue(InsertionProperty);}
set{SetValue(InsertionProperty,value);}
}
公共静态只读DependencyProperty InsertionProperty=
DependencyProperty.Register(“插入”)、typeof(字符串)、typeof(PersonNameControl),
新的FrameworkPropertyMetadata(“,FrameworkPropertyMetadataOptions.bindstwoway默认值));
公共字符串姓氏
{
获取{return(string)GetValue(LastnameProperty);}
set{SetValue(LastnameProperty,value);}
}
公共静态只读DependencyProperty LastnameProperty=
DependencyProperty.Register(“姓氏”、typeof(字符串)、typeof(PersonNameControl),
新的FrameworkPropertyMetadata(“,FrameworkPropertyMetadataOptions.bindstwoway默认值));
}
该控件应在另一个视图中使用,如下所示:


当ViewModel(实现INotifyDataErrorInfo)创建验证错误时,my
PersonNameControl
UserControl不会发生任何事情。 我设法创建了一个独立的控件,因为它不依赖于特定的DataContext,不在其codebehind文件中设置自己的DataContext,只通过依赖属性获取其值。值通过绑定交换并显示,但验证错误不会显示。 我想要的是将验证错误传递给UserControl

互联网上的一些解决方案利用了
validationadrnersite
,我试过了。但这只适用于一个
文本框

如果不让我的控制依赖于外部世界或引入丑陋的额外属性来解决它,我看不到任何解决方案。我认为错误就像一条信息一样通过所有绑定“隧道”到值到达的最后一级。但这似乎不是正确的考虑

编辑:

我添加了ViewModel类

公共类CustomPerformViewModel:ViewModelBase,INotifyDataErrorInfo { 受保护的字符串\u clientNumber; 受保护日期时间\日期; 受保护字符串_firstname; 受保护的字符串\u插入; 受保护字符串\u lastname; 受保护地址\u地址; 受保护的可观察收集电子邮件; 受保护的可观察收集电话号码; 受保护字符串\u注释; 受保护的bool\u hasserrors; 受保护的IList\u验证错误; 公共IList验证错误 { 获取{return\u validationErrors;} 设置{u validationErrors=value;OnPropertyChanged(“validationErrors”);} } 公共字符串ClientNumber { 获取{return\u clientNumber;} 设置{u clientNumber=value;OnPropertyChanged(“clientNumber”);} } 公共日期时间日期 { 获取{return\u date;} 设置{u date=value;OnPropertyChanged(“日期”);} } 公共字符串名 { 获取{return\u firstname;} 设置{u firstname=value;OnPropertyChanged(“firstname”);} } 公共字符串插入 { 获取{return\u insertion;} 设置{u insertion=value;OnPropertyChanged(“insertion”);} } 公共字符串姓氏 { 获取{return\u lastname;} 设置{u lastname=value;OnPropertyChanged(“lastname”);} } 公共广播 { 获取{return\u address;} 设置{u address=value;OnPropertyChanged(“地址”);} } 公开收集电子邮件 { 获取{返回_电子邮件;} 设置{u emails=value;OnPropertyChanged(“emails”);} } 公共可观测收集电话号码 { 获取{return\u phoneNumbers;} 设置{u phoneNumbers=value;OnPropertyChanged(“phoneNumbers”);} } 公共字符串注释 { 获取{return\u note;} 设置{u note=value;OnPropertyChanged(“note”);} } 私有DelegateCommand_saveCustomerCommand; 公共DelegateCommand SaveCustomerCommand { 获取{return\u saveCustomerCommand;} 私有集{u saveCustomerCommand=value;OnPropertyChanged(“saveCustomerCommand”);} } 公共自定义视图模型() { ValidationErrors=新列表(); SaveCustomerCommand=newdelegateCommand(SaveCustomer,CanSaveCustomer); } 受保护的void ValidateInput() { ValidationErrors.Clear(); 客户有效
<Window
    x:Class="ValidationSubUI.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:ValidationSubUI"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Name="MyWindow"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>
    <Grid>
        <local:SubUserControl
            FirstName="{Binding FirstName, Mode=TwoWay}"
            LastName="{Binding LastName, Mode=TwoWay}"
            ValidationSource="{Binding ElementName=MyWindow, Path=DataContext}" />
    </Grid>
</Window>
using GalaSoft.MvvmLight;
using System.ComponentModel;

namespace ValidationSubUI
{
    public class MainViewModel : ViewModelBase, IDataErrorInfo
    {
        public string Error
        {
            get
            {
                return string.Empty;
            }
        }

        private string m_FirstName;
        public string FirstName
        {
            get { return m_FirstName; }
            set
            {
                m_FirstName = value;
                RaisePropertyChanged();
            }
        }

        private string m_LastName;
        public string LastName
        {
            get { return m_LastName; }
            set
            {
                m_LastName = value;
                RaisePropertyChanged();
            }
        }


        public string this[string columnName]
        {
            get
            {
                if (columnName == nameof(FirstName))
                {
                    return GetFirstNameError();
                }
                else if (columnName == nameof(LastName))
                {
                    return GetLastNameError();
                }

                return null;
            }
        }

        private string GetFirstNameError()
        {
            string result = string.Empty;

            if (string.IsNullOrEmpty(FirstName))
            {
                result = "First name required";
            }

            return result;
        }

        private string GetLastNameError()
        {
            string result = string.Empty;

            if (string.IsNullOrEmpty(LastName))
            {
                result = "Last name required";
            }

            return result;
        }
    }
}
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace ValidationSubUI
{
    /// <summary>
    /// Interaction logic for SubUserControl.xaml
    /// </summary>
    public partial class SubUserControl : UserControl, IDataErrorInfo
    {
        public SubUserControl()
        {
            InitializeComponent();
        }

        public IDataErrorInfo ValidationSource
        {
            get { return (IDataErrorInfo)GetValue(ValidationSourceProperty); }
            set { SetValue(ValidationSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ValidationSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValidationSourceProperty =
            DependencyProperty.Register("ValidationSource", typeof(IDataErrorInfo), typeof(SubUserControl), new PropertyMetadata(null));



        public string FirstName
        {
            get { return (string)GetValue(FirstNameProperty); }
            set { SetValue(FirstNameProperty, value); }
        }

        // Using a DependencyProperty as the backing store for FirstName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FirstNameProperty =
            DependencyProperty.Register("FirstName", typeof(string), typeof(SubUserControl), new PropertyMetadata(string.Empty));



        public string LastName
        {
            get { return (string)GetValue(LastNameProperty); }
            set { SetValue(LastNameProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LastName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LastNameProperty =
            DependencyProperty.Register("LastName", typeof(string), typeof(SubUserControl), new PropertyMetadata(string.Empty));


        public string Error
        {
            get
            {
                return string.Empty;
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (ValidationSource != null)
                {
                    return ValidationSource[columnName];
                }

                return null;
            }
        }
    }
}
<UserControl
    x:Class="ValidationSubUI.SubUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Name="CustomControl"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">

    <UserControl.Resources>

        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <DockPanel>
                            <Border BorderBrush="Red" BorderThickness="1">
                                <AdornedElementPlaceholder x:Name="controlWithError" />
                            </Border>
                            <TextBlock
                                Margin="5,0,0,0"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                FontSize="12"
                                FontWeight="DemiBold"
                                Foreground="Red"
                                Text="{Binding ElementName=controlWithError, Path=AdornedElement.ToolTip, Mode=OneWay}" />
                        </DockPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
                </Trigger>
            </Style.Triggers>
        </Style>

    </UserControl.Resources>

    <Grid DataContext="{x:Reference Name=CustomControl}">
        <StackPanel>
            <TextBox
                Width="120"
                Height="30"
                Margin="5"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Text="{Binding FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}"
                TextWrapping="Wrap" />

            <TextBox
                Width="120"
                Height="30"
                Margin="5"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Text="{Binding LastName, Mode=TwoWay, ValidatesOnDataErrors=True}"
                TextWrapping="Wrap" />
        </StackPanel>
    </Grid>
</UserControl>