• silverlight wpf Command提交时输入验证


    silverlight 或WPF在MVVM模式中使用INotifyDataErrorInfo接口对输入进行验证时

    控件lostFocus时会触发验证,但在提交动作(例如button的Command)时,不触发

    验证。下面的方法提供控件输入验证统一触发。

    1、添加ValidationScope类

    public class ValidationScope
        {
            public FrameworkElement ScopeElement { get; private set; }
    
            private readonly ObservableCollection<ValidationError> _errors = new ObservableCollection<ValidationError>();
    
            public ObservableCollection<ValidationError> Errors
            {
                get { return _errors; }
            }
    
            public bool IsValid()
            {
                return _errors.Count == 0;
            }
    
            public static string GetValidateBoundProperty(DependencyObject obj)
            {
                return (string)obj.GetValue(ValidateBoundPropertyProperty);
            }
    
            public static void SetValidateBoundProperty(DependencyObject obj, string value)
            {
                obj.SetValue(ValidateBoundPropertyProperty, value);
            }
    
            public static readonly DependencyProperty ValidateBoundPropertyProperty =
                DependencyProperty.RegisterAttached("ValidateBoundProperty", typeof(string), typeof(ValidationScope), new PropertyMetadata(null));
    
            public static ValidationScope GetValidationScope(DependencyObject obj)
            {
                return (ValidationScope)obj.GetValue(ValidationScopeProperty);
            }
    
            public static void SetValidationScope(DependencyObject obj, ValidationScope value)
            {
                obj.SetValue(ValidationScopeProperty, value);
            }
    
            public static readonly DependencyProperty ValidationScopeProperty =
                DependencyProperty.RegisterAttached("ValidationScope", typeof(ValidationScope), typeof(ValidationScope), new PropertyMetadata(null, ValidationScopeChanged));
    
            private static void ValidationScopeChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
            {
                ValidationScope oldScope = args.OldValue as ValidationScope;
                if (oldScope != null)
                {
                    oldScope.ScopeElement.BindingValidationError -= oldScope.ScopeElement_BindingValidationError;
                    oldScope.ScopeElement = null;
                }
    
                FrameworkElement scopeElement = source as FrameworkElement;
                if (scopeElement == null)
                {
                    throw new ArgumentException(string.Format(
                        "'{0}' is not a valid type.ValidationScope attached property can only be specified on types inheriting from FrameworkElement.",
                        source));
                }
    
                ValidationScope newScope = (ValidationScope)args.NewValue;
                newScope.ScopeElement = scopeElement;
                newScope.ScopeElement.BindingValidationError += newScope.ScopeElement_BindingValidationError;
            }
    
            private void ScopeElement_BindingValidationError(object sender, ValidationErrorEventArgs e)
            {
                if (e.Action == ValidationErrorEventAction.Removed)
                {
                    Errors.Remove(e.Error);
                }
                else if (e.Action == ValidationErrorEventAction.Added)
                {
                    Errors.Add(e.Error);
                }
            }
    
            public void ValidateScope()
            {
                ForEachElement(ScopeElement, delegate(DependencyObject obj)
                {
                    // TODO - some of this reflection could be cached to improve performance
                    string propertyName = GetValidateBoundProperty(obj);
                    if (!string.IsNullOrEmpty(propertyName))
                    {
                        FrameworkElement element = (FrameworkElement)obj;
                        var field = element.GetType().GetFields(BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Public)
                            .Where(p => p.FieldType == typeof(DependencyProperty) && p.Name == (propertyName + "Property"))
                            .FirstOrDefault();
    
                        if (field == null)
                        {
                            throw new ArgumentException(string.Format(
                                "Dependency property '{0}' could not be found on type '{1}'; ValidationScope.ValidateBoundProperty",
                                propertyName, element.GetType()));
                        }
                        var be = element.GetBindingExpression((DependencyProperty)field.GetValue(null));
                        be.UpdateSource();
                    }
                });
            }
    
            private static void ForEachElement(DependencyObject root, Action<DependencyObject> action)
            {
                int childCount = VisualTreeHelper.GetChildrenCount(root);
                for (int i = 0; i < childCount; i++)
                {
                    var obj = VisualTreeHelper.GetChild(root, i);
                    action(obj);
                    ForEachElement(obj, action);
                }
            }
        }

    2、在包含输入控件的容器控件添加依赖属性ValidationScope(ViewModel里的ValidationScope实例)

    xaml:

    <containers:ContainerPanel Grid.Row="1" Margin="10" Title="挂起工单列表" TitleHorizontalAlignment="Left" TitleMargin="10,10,0,10" validation:ValidationScope.ValidationScope="{Binding ValidationScope1}">

    3、每个需要验证的控件添加依赖属性ValidateBound,指定要验证控件的哪个属性

        <TextBox  Text="{Binding ApproveContent,Mode=TwoWay}" validation:ValidationScope.ValidateBoundProperty="Text"/>

    4、ViewModel中定义ValidationScope实例

    private ValidationScope _validationScope1 = new ValidationScope();
            public ValidationScope ValidationScope1
            {
                get { return _validationScope1; }
                set
                {
                    _validationScope1 = value;
                    this.RaisePropertyChanged(() => ValidationScope1);
                }
            }

    5、在要触发验证的Command中调用验证方法

    public DelegateCommand ApproveCommand
            {
                get
                {
                    if (_approveCommand == null)
                    {
                        _approveCommand = new DelegateCommand(() =>
                        {
                            ValidationScope1.ValidateScope();
    
                            if (!ValidationScope1.IsValid())
                            {
                                CommonNotification.Raise(new Notification() { Content = new UWay.NOAP.DTO.MsgInfo() { IsSuccess = true, Content = "要审批的工单需要填写审批内容!" }, Title = "提示" });
                            }
                            else
                            {
                                ApproveBatch();
                            }
    
                        }, () => _canApprove);
                    }
                    return _approveCommand;
                }
            }
  • 相关阅读:
    牛客小白赛23
    三分查找模板和例题
    链式前向星存图模板
    树形dp求解树的重心和例题
    P3915-树的分解-(dfs)
    P2119 魔法阵-(桶排序+前后缀和)
    小阳的贝壳-(差分+线段树+gcd)
    NOJ1370: [蓝桥杯2018初赛]测试次数-(dp)
    begin.lydsy 入门OJ题库:3611-3613:神炎皇、降雷皇、幻魔皇
    1797: [Noi2010]海拔
  • 原文地址:https://www.cnblogs.com/akiing/p/4030332.html
Copyright © 2020-2023  润新知