WPF使用MVVM时,表单验证


    
    
    
    
    

  
    
    
    
    
    

 
    
    
    
    
    
    
    
    
    
        
        
    

错误提示模板:



            
                
                    
                    
                
                
                    
                
            
        
        
    


应用场景描述:表单中TextBox数据验证条件依赖其他TextBox数据(例:腹板T<0.5*底板W)。

问题1:先录入腹板T数据,后录入底板W数据,不能触发腹板T 数据验证。

解决方法1:底板W加入和腹板T相关的验证,实现双向关联验证。优点,解决方式简单;缺点,用户体验差,增加表验证逻辑复杂性(整个表单校验时,校验失败,2选1提示数据内容)。

方法2:终端校验,保存按钮触发整个表单校验。优点:减少表单验证条件。缺点:验证条件依赖其他TextBox数据的校验,需要保存按钮触发校验提示。

问题2:表单验证失败,保存按钮不提交数据。(能力原因,没有找到ViewModel中校验整个表单的方式(╯︵╰),有大神请赐教。

方法1:cs代码中添加保存按钮Click事件,返回整个表单验证结果给ViewModel。(关键内容校验控件的 ((TextBox)controlName).GetBindingExpression(TextBox.TextProperty).UpdateTarget()

ViewModel代码:

public class WorksManageViewModel : NotificationObject, IDataErrorInfo
{
        /// 
        /// 底板厚
        /// 
        public decimal H_H
        {
            get { return MainSelect.H_H; }
            set { MainSelect.H_H = value; this.RaisePropertyChanged("H_H"); }
        }
        /// 
        /// 底板宽
        /// 
        public decimal H_B
        {
            get { return MainSelect.H_B; }
            set { MainSelect.H_B = value; this.RaisePropertyChanged("H_B");}
        }
        /// 
        /// 腹板厚
        /// 
        public decimal H_T2
        {
            get { return MainSelect.H_T2; }
            set { MainSelect.H_T2 = value; this.RaisePropertyChanged("H_T2"); }
        }
        /// 
        /// 腹板宽
        /// 
        public decimal H_D
        {
            get { return MainSelect.H_D; }
            set { MainSelect.H_D = value; this.RaisePropertyChanged("H_D"); }
        }
        /// 
        /// 面板厚
        /// 
        public decimal B_H1
        {
            get { return MainSelect.B_H1; }
            set { MainSelect.B_H1 = value; this.RaisePropertyChanged("B_H1");}
        }
        /// 
        /// 面板宽
        /// 
        public decimal B_H2
        {
            get { return MainSelect.B_H2; }
            set { MainSelect.B_H2 = value; this.RaisePropertyChanged("B_H2"); }
        }
        /// 
        /// 箱体长度
        /// 
        public decimal H_T1
        {
            get { return MainSelect.H_T1; }
            set { MainSelect.H_T1 = value; this.RaisePropertyChanged("H_T1"); }
        }
        public string this[string columnName]
        {
            get { return GetErrorFor(columnName); }
        }
        private string _error;
        public string Error
        {
            get { return _error; }
            set { _error = value; }
        }
        /// 
        /// 校验方式
        /// 
        /// 
        /// 
        public string GetErrorFor(string columnName)
        {
            switch (columnName)
            {
                case "H_H":
                    if (0 >= H_H) return columnName + " 必须大于0"; break;
                case "H_B":
                    if (0 >= H_B) return columnName + " 必须大于0"; break;
                case "H_T2":
                    if (0 >= H_T2) return columnName + " 必须大于0";
                    if (2 * H_T2 >= H_B) return columnName + string.Format(" 必须小于(0.5*底板W){0}", (H_B / 2).ToString());
                    break;
                case "H_D":
                    if (0 >= H_D) return columnName + " 必须大于0"; break;
                case "B_H1":
                    if (0 >= B_H1) return columnName + " 必须大于0";
                    else
                    {
                        switch (CoverPlateType)
                        {
                            case 1:
                                if (B_H1 >= H_D)
                                {
                                    return columnName + string.Format(" 必须小于(腹板W){0}", H_D.ToString());
                                }
                                break;
                        }
                    }
                    break;
                case "B_H2":
                    switch (CoverPlateType)
                    {
                        case 0:
                            if (2 * H_T2 >= B_H2)
                                return columnName + string.Format(" 必须大于(2*腹板T){0}", (2 * H_T2).ToString());
                            break;
                        case 1:
                            if (B_H2 >= H_B - 2 * H_T2)
                            {
                                return columnName + string.Format(" 必须大于(底板W-2*腹板T){0}", (H_B - 2 * H_T2).ToString());
                            }
                            break;
                    }
                    break;
                case "H_T1":
                    if (0 >= H_T1)
                        return columnName + " 必须大于0";
                    break;
            }
            return "";
        }
}

cs文件代码:

        private void saveButton_Click(object sender, RoutedEventArgs e)
        {
            ((WorksManageViewModel)this.DataContext).IsValid = IsValid(this);
        }
        // Validate all dependency objects in a window
        bool IsValid(DependencyObject node)
        {
            // Check if dependency object was passed
            if (node != null)
            {
                //Check DependencyObject is TextBox 
                //NOTE:Update DataSource Binding
                if (node is TextBox)
                {
                    BindingExpression binding = ((TextBox)node).GetBindingExpression(TextBox.TextProperty);
                    binding.UpdateTarget();
                }
                // Check if dependency object is valid.
                // NOTE: Validation.GetHasError works for controls that have validation rules attached 
                bool isValid = !Validation.GetHasError(node);
                if (!isValid)
                {
                    // If the dependency object is invalid, and it can receive the focus,
                    // set the focus
                    if (node is IInputElement) Keyboard.Focus((IInputElement)node);
                    return false;
                }
            }
            // If this dependency object is valid, check all child dependency objects
            foreach (object subnode in LogicalTreeHelper.GetChildren(node))
            {
                if (subnode is DependencyObject)
                {
                    // If a child dependency object is invalid, return false immediately,
                    // otherwise keep checking
                    if (IsValid((DependencyObject)subnode) == false) return false;
                }
            }
            // All dependency objects are valid
            return true;
        }



你可能感兴趣的:(WPF)