Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.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/1/ssh/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# WPF数据批注验证问题_C#_Wpf_Validation_Mvvm_Data Annotations - Fatal编程技术网

C# WPF数据批注验证问题

C# WPF数据批注验证问题,c#,wpf,validation,mvvm,data-annotations,C#,Wpf,Validation,Mvvm,Data Annotations,我主要是网页开发人员,我是超级新的WPF。我正在努力工作的WPF项目之一。我很难使用数据注释和MVVM验证模型。有人能告诉我我可能做错了什么吗。 让我从我的模型开始: public class FamilyMember : PropertyChangedNotification { public long FamilyMemberId { get; set; } [Required(ErrorMessage = "First Name is re

我主要是网页开发人员,我是超级新的WPF。我正在努力工作的WPF项目之一。我很难使用数据注释和MVVM验证模型。有人能告诉我我可能做错了什么吗。 让我从我的模型开始:

public class FamilyMember : PropertyChangedNotification
    {
        public long FamilyMemberId { get; set; }
        [Required(ErrorMessage = "First Name is required")]
        [RegularExpression(@"^[a-zA-Z''-'\s]{2,40}$")]
        public string FirstName { get; set; }

       [Required(ErrorMessage = "Last Name is required")]
        public string LastName { get; set; }
    }
这是我的PropertyChangedNotification课程

public abstract class PropertyChangedNotification : INotifyPropertyChanged, IDataErrorInfo
    {
        #region Fields

        private readonly Dictionary<string, object> _values = new Dictionary<string, object>();

        #endregion

        #region Protected

        /// <summary>
        /// Sets the value of a property.
        /// </summary>
        /// <typeparam name="T">The type of the property value.</typeparam>
        /// <param name="propertySelector">Expression tree contains the property definition.</param>
        /// <param name="value">The property value.</param>
        protected void SetValue<T>(Expression<Func<T>> propertySelector, T value)
        {
            string propertyName = GetPropertyName(propertySelector);

            SetValue<T>(propertyName, value);
        }

        /// <summary>
        /// Sets the value of a property.
        /// </summary>
        /// <typeparam name="T">The type of the property value.</typeparam>
        /// <param name="propertyName">The name of the property.</param>
        /// <param name="value">The property value.</param>
        protected void SetValue<T>(string propertyName, T value)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentException("Invalid property name", propertyName);
            }

            _values[propertyName] = value;
            NotifyPropertyChanged(propertyName);
        }

        /// <summary>
        /// Gets the value of a property.
        /// </summary>
        /// <typeparam name="T">The type of the property value.</typeparam>
        /// <param name="propertySelector">Expression tree contains the property definition.</param>
        /// <returns>The value of the property or default value if not exist.</returns>
        protected T GetValue<T>(Expression<Func<T>> propertySelector)
        {
            string propertyName = GetPropertyName(propertySelector);

            return GetValue<T>(propertyName);
        }

        /// <summary>
        /// Gets the value of a property.
        /// </summary>
        /// <typeparam name="T">The type of the property value.</typeparam>
        /// <param name="propertyName">The name of the property.</param>
        /// <returns>The value of the property or default value if not exist.</returns>
        protected T GetValue<T>(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentException("Invalid property name", propertyName);
            }

            object value;
            if (!_values.TryGetValue(propertyName, out value))
            {
                value = default(T);
                _values.Add(propertyName, value);
            }

            return (T)value;
        }

        /// <summary>
        /// Validates current instance properties using Data Annotations.
        /// </summary>
        /// <param name="propertyName">This instance property to validate.</param>
        /// <returns>Relevant error string on validation failure or <see cref="System.String.Empty"/> on validation success.</returns>
        protected virtual string OnValidate(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentException("Invalid property name", propertyName);
            }

            string error = string.Empty;
            var value = GetValue(propertyName);
            var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1);
            var result = Validator.TryValidateProperty(
                value,
                new ValidationContext(this, null, null)
                {
                    MemberName = propertyName
                },
                results);

            if (!result)
            {
                var validationResult = results.First();
                error = validationResult.ErrorMessage;
            }

            return error;
        }

        #endregion

        #region Change Notification

        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The property that has a new value.</param>
        protected void NotifyPropertyChanged(string propertyName)
        {
            this.VerifyPropertyName(propertyName);

            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        protected void NotifyPropertyChanged<T>(Expression<Func<T>> propertySelector)
        {
            var propertyChanged = PropertyChanged;
            if (propertyChanged != null)
            {
                string propertyName = GetPropertyName(propertySelector);
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion // INotifyPropertyChanged Members

        #region Data Validation

        string IDataErrorInfo.Error
        {
            get
            {
                throw new NotSupportedException("IDataErrorInfo.Error is not supported, use IDataErrorInfo.this[propertyName] instead.");
            }
        }

        string IDataErrorInfo.this[string propertyName]
        {
            get
            {
                return OnValidate(propertyName);
            }
        }

        #endregion

        #region Privates

        private string GetPropertyName(LambdaExpression expression)
        {
            var memberExpression = expression.Body as MemberExpression;
            if (memberExpression == null)
            {
                throw new InvalidOperationException();
            }

            return memberExpression.Member.Name;
        }

        private object GetValue(string propertyName)
        {
            object value;
            if (!_values.TryGetValue(propertyName, out value))
            {
                var propertyDescriptor = TypeDescriptor.GetProperties(GetType()).Find(propertyName, false);
                if (propertyDescriptor == null)
                {
                    throw new ArgumentException("Invalid property name", propertyName);
                }

                value = propertyDescriptor.GetValue(this);
                _values.Add(propertyName, value);
            }
            var propertyDescriptor1 = TypeDescriptor.GetProperties(GetType()).Find(propertyName, false);
            if (propertyDescriptor1 == null)
            {
                throw new ArgumentException("Invalid property name", propertyName);
            }

            value = propertyDescriptor1.GetValue(this);
            return value;
        }

        #endregion

        #region Debugging

        /// <summary>
        /// Warns the developer if this object does not have
        /// a public property with the specified name. This
        /// method does not exist in a Release build.
        /// </summary>
        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public void VerifyPropertyName(string propertyName)
        {
            // Verify that the property name matches a real, 
            // public, instance property on this object.
            if (TypeDescriptor.GetProperties(this)[propertyName] == null)
            {
                string msg = "Invalid property name: " + propertyName;

                if (this.ThrowOnInvalidPropertyName)
                    throw new Exception(msg);
                else
                    Debug.Fail(msg);
            }
        }

        /// <summary>
        /// Returns whether an exception is thrown, or if a Debug.Fail() is used
        /// when an invalid property name is passed to the VerifyPropertyName method.
        /// The default value is false, but subclasses used by unit tests might
        /// override this property's getter to return true.
        /// </summary>
        protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

        #endregion // Debugging Aides
    }
现在的问题是: 如果我将用户控件的dataContext设置为FamilyMemberViewModel.SharedViewModel(),则不会显示验证。。 一旦我将DataContext设置为FamilyMember的实例,它就会显示出来

由于这是一个MVVM模式,我不想直接将我的模型引用到view plus中,我有一个RelayCommand,在出现任何验证错误时启用和禁用Save按钮

这是我在用户控件中直接引用模型的新实例时的屏幕截图(请原谅我的丑陋视图)

以下是我将ViewModel引用为DataContext时的屏幕截图:

我非常接近验证模型的正确方法(至少我认为是这样,因为我来自web开发环境,过去使用过数据注释验证),但无法找出它的错误。 我将感谢更多的解释,因为我是WPF的新手

谢谢

现在的问题是:如果我将用户控件的dataContext设置为FamilyMemberViewModel.SharedViewModel(),则不会显示验证。。一旦我将DataContext设置为FamilyMember的实例,它就会显示出来

这是因为FamilyMemberViewModel类没有您在视图中绑定到的名为“FirstName”和“LastName”的属性,因此绑定将失败

在XAML中设置绑定时,绑定到元素的DataContext属性

如果绑定到DataContext的NewFamilyMember属性的FirstName和LastName属性,即FamilyMemberViewModel.SharedViewModel()方法返回的FamilyMemberViewModel对象,则它应该可以工作:

<StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal">
    <TextBox  Margin="10,0,0,10" x:Name="FirstName" Text="{Binding NewFamilyMember.FirstName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Validation.Error="Validation_Error" Width="100"/>
    <TextBlock Style="{StaticResource TextBlockStyle}" Text="{Binding (Validation.Errors)[0].ErrorContent, ElementName=FirstName}" Margin="10,0,0,10"/>
</StackPanel>

<Label Target="{Binding ElementName=LastName}" Grid.Row="1" Grid.Column="0">Last Name:</Label>
<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" x:Name="LastName" Text="{Binding NewFamilyMember.LastName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Validation.Error="Validation_Error"/>
<Button Content="Save" Grid.Column="1" HorizontalAlignment="Center" Grid.Row="2" VerticalAlignment="Top" Width="75" Margin="0,20,0,0" Command="{Binding SaveCommand}"/>

姓氏:

非常感谢。那正是我错过的不客气。如果答案对你有帮助,请记得投赞成票。
<UserControl x:Class="MyApp.Resources.AddMember"
             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" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <Style x:Key="TextBlockStyle" TargetType="{x:Type TextBlock}">
            <Setter Property="FontSize" Value="16"/>
            <Setter Property="Margin" Value="0,5,0,0"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="Foreground" Value="Red"></Setter>
        </Style>
        <Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
            <Setter Property="FontSize" Value="16"/>
            <Setter Property="Margin" Value="0,5,0,0"/>
        </Style>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="FontSize" Value="16"/>
            <Setter Property="Margin" Value="0,5,0,0"/>
        </Style>
    </UserControl.Resources>
    
    <Grid Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        
        <Label Target="{Binding ElementName=FirstName}" Grid.Row="0" Grid.Column="0">First Name:</Label>
        <StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal">
            <TextBox  Margin="10,0,0,10" x:Name="FirstName" Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Validation.Error="Validation_Error" Width="100"/>
            <TextBlock Style="{StaticResource TextBlockStyle}" Text="{Binding (Validation.Errors)[0].ErrorContent, ElementName=FirstName}" Margin="10,0,0,10"/>
        </StackPanel>
        
        <Label Target="{Binding ElementName=LastName}" Grid.Row="1" Grid.Column="0">Last Name:</Label>
        <TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" x:Name="LastName" Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Validation.Error="Validation_Error"/>
        <Button Content="Save" Grid.Column="1" HorizontalAlignment="Center" Grid.Row="2" VerticalAlignment="Top" Width="75" Margin="0,20,0,0" Command="{Binding SaveCommand}"/>
    </Grid>
</UserControl>
public partial class AddMember : UserControl
    {
        private int _noOfErrorsOnScreen = 0;
        private FamilyMember _member = new FamilyMember();
        public AddMember()
        {
            InitializeComponent();
            //this.DataContext = _member;
            this.DataContext = FamilyMemberViewModel.SharedViewModel();
           
        }
        private void Validation_Error(object sender, ValidationErrorEventArgs e)
        {
            if (e.Action == ValidationErrorEventAction.Added) FamilyMemberViewModel.Errors += 1;
            if (e.Action == ValidationErrorEventAction.Removed) FamilyMemberViewModel.Errors -= 1;
        }      

    }
<StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal">
    <TextBox  Margin="10,0,0,10" x:Name="FirstName" Text="{Binding NewFamilyMember.FirstName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Validation.Error="Validation_Error" Width="100"/>
    <TextBlock Style="{StaticResource TextBlockStyle}" Text="{Binding (Validation.Errors)[0].ErrorContent, ElementName=FirstName}" Margin="10,0,0,10"/>
</StackPanel>

<Label Target="{Binding ElementName=LastName}" Grid.Row="1" Grid.Column="0">Last Name:</Label>
<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" x:Name="LastName" Text="{Binding NewFamilyMember.LastName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Validation.Error="Validation_Error"/>
<Button Content="Save" Grid.Column="1" HorizontalAlignment="Center" Grid.Row="2" VerticalAlignment="Top" Width="75" Margin="0,20,0,0" Command="{Binding SaveCommand}"/>