WPF 使用绑定验证实现输入验证通过后才可提交

参考

环境

软件/系统 版本 说明
Windows windows 10 专业版 22H2 64 位操作系统, 基于 x64 的处理器
Microsoft Visual Studio Community 2022 (64 位) - Current 版本 17.14.9
Prism Template Pack 2.4.1 Microsoft Visual Studio 扩展
.NET 6
Prism.Unity 8.1.97 nuget依赖库(使用 Prism Template Pack 创建项目时选择的容器,使用模板创建的项目自动安装)
MaterialDesignThemes 5.2.1 nuget依赖库

正文

步骤

  1. 实现 AccountLoginValidationRule.cs
  2. Login.xaml 页面附加属性类的命名空间 xmlns:validationRule="clr-namespace:WPFNetConnect.ValidationRules"
  3. 在控件中使用
    <TextBox x:Name="LoginAccountTextBox" Style="{StaticResource LoginAccountTextBox}">
    	<Binding Path="Account">
    		<Binding.ValidationRules>
    			<!--  可以带参数,可以多条条件  -->
    			<!--  validationRule:AccountLoginValidationRule Min="2" /  -->
    			<!--  validationRule:AccountLoginValidationRule Min="2" Max="10" /  -->
    			<validationRule:AccountLoginValidationRule />
    		</Binding.ValidationRules>
    	</Binding>
    </TextBox>
    
  4. 提交命令在创建时,也要编写 CanExecute 逻辑,否则首次初始化,绑定验证默认为True,导致提交按钮可用

主要代码

  1. AccountLoginValidationRule.cs
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Security.Principal;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Controls;
    using System.Windows.Input;
    // https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/data/how-to-implement-binding-validation
    namespace WPFNetConnect.ValidationRules
    {
    	class AccountLoginValidationRule : ValidationRule
    	{
    		/// <summary>
    		/// 最短长度
    		/// </summary>
    		public byte Min { get; set; } = 8;
    		/// <summary>
    		/// 最大长度
    		/// </summary>
    		public byte Max { get; set; } = 16;
    
    		public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    		{
    			var val = value as string;
    			if (string.IsNullOrEmpty(val))
    			{
    				return new ValidationResult(false, "请输入正确的账号");
    			}
    			if (val.Length < Min || val.Length > Max)
    			{
    				return new ValidationResult(false, "请输入正确的账号");
    			}
    			return ValidationResult.ValidResult;
    		}
    	}
    }
    
    
  2. Login.xaml
    <Window
    	x:Class="WPFNetConnect.Views.Login"
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:helper="clr-namespace:WPFNetConnect.Helper"
    	xmlns:prism="http://prismlibrary.com/"
    	xmlns:validationRule="clr-namespace:WPFNetConnect.ValidationRules"
    	Title="{Binding Title}"
    	Width="1280"
    	Height="800"
    	prism:ViewModelLocator.AutoWireViewModel="True"
    	WindowStartupLocation="CenterScreen">
    	<Window.Resources>
    		<ResourceDictionary>
    			<!--  单独引入外部样式  -->
    			<ResourceDictionary.MergedDictionaries>
    				<ResourceDictionary Source="/Styles/LoginStyle.xaml" />
    			</ResourceDictionary.MergedDictionaries>
    		</ResourceDictionary>
    	</Window.Resources>
    	<Grid>
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Width="512" />
    			<ColumnDefinition />
    		</Grid.ColumnDefinitions>
    		<Image Grid.Column="0" Style="{StaticResource LoginLeft}" />
    		<StackPanel Grid.Column="1" Style="{StaticResource LoginRight}">
    			<Label Style="{StaticResource LoginTitle}">欢迎回来</Label>
    			<Label Style="{StaticResource LoginDesc}">登陆到您的账户</Label>
    			<Label Style="{StaticResource LoginAccountTitle}">用户名</Label>
    			<TextBox x:Name="LoginAccountTextBox" Style="{StaticResource LoginAccountTextBox}">
    				<Binding Path="Account">
    					<Binding.ValidationRules>
    						<!--  可以带参数,可以多条条件  -->
    						<!--  validationRule:AccountLoginValidationRule Min="2" /  -->
    						<!--  validationRule:AccountLoginValidationRule Min="2" Max="10" /  -->
    						<validationRule:AccountLoginValidationRule />
    					</Binding.ValidationRules>
    				</Binding>
    			</TextBox>
    			<Label Style="{StaticResource LoginPasswordTitle}">密码</Label>
    			<PasswordBox
    				x:Name="LoginPasswordBox"
    				helper:PasswordBoxHelper.Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
    				Style="{StaticResource LoginPasswordBox}" />
    			<Button
    				Command="{Binding SubmitBtnCommand}"
    				Content="登录"
    				Style="{StaticResource LoginSubmitButton}" />
    			<Label Style="{StaticResource LoginErrorTip}">无法登录?联系管理员</Label>
    		</StackPanel>
    		<Label
    			Grid.Column="1"
    			Content="NetConnect v1.0.5"
    			Style="{StaticResource LoginVersion}" />
    	</Grid>
    </Window>
    
    
  3. LoginViewModel.cs
    using log4net;
    using Prism.Commands;
    using Prism.Mvvm;
    using System;
    using System.CodeDom.Compiler;
    using System.Diagnostics;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace WPFNetConnect.ViewModels
    {
    	public class LoginViewModel : BindableBase
    	{
    		private static readonly ILog _logger = LogManager.GetLogger(typeof(LoginViewModel));
    
    		private string _title = "Login";
    		public string Title
    		{
    			get { return _title; }
    			set { SetProperty(ref _title, value); }
    		}
    		private string _account = "";
    		public string Account
    		{
    			get { return _account; }
    			set { 
    				SetProperty(ref _account, value);
    				// 当账号或密码改变时,重新计算提交按钮的可执行状态
    				SubmitBtnCommand?.RaiseCanExecuteChanged(); 
    			}
    		}
    		private string _password = "";
    		public string Password
    		{
    			get { return _password; }
    			set { 
    				SetProperty(ref _password, value);
    				// 当账号或密码改变时,重新计算提交按钮的可执行状态
    				SubmitBtnCommand?.RaiseCanExecuteChanged(); 
    			}
    		}
    		/// <summary>
    		/// 点击登录按钮的命令
    		/// </summary>
    		public DelegateCommand SubmitBtnCommand { get; set; }
    
    		/// <summary>
    		/// 是否可以提交  
    		/// </summary>
    		/// <returns></returns>
    		public bool SubmitBtnCommandCanExecute()
    		{
    			return !string.IsNullOrEmpty(Account) && !string.IsNullOrEmpty(Password);
    		}
    
    		/// <summary>
    		/// 点击登录按钮的执行方法
    		/// </summary>
    		public void SubmitBtnCommandExecute()
    		{
    			_logger.Info("点击登录");
    			Debug.WriteLine(Account);
    			Debug.WriteLine(Password);
    			if ("admin".Equals(Account) && "123456".Equals(Password))
    			{
    				System.Windows.MessageBox.Show("登录成功");   
    				// Application.Current.MainWindow 就是当前的主窗口
    				var loginView =  Application.Current.MainWindow;
    				// 使用Prism框架的依赖注入容器来创建主窗口
    				var mainView = Container.Resolve<MainWindow>();
    				// 重新指定主窗口
    				Application.Current.MainWindow = mainView;
    				mainView.Show();
    				loginView.Close();
    			}
    			else
    			{
    				System.Windows.MessageBox.Show("登录失败");
    			}
    		}
    
    		public LoginViewModel()
    		{
    			SubmitBtnCommand = new DelegateCommand(SubmitBtnCommandExecute, SubmitBtnCommandCanExecute);
    		}
    	}
    }
    
    
posted @ 2025-07-18 14:46  夏秋初  阅读(21)  评论(0)    收藏  举报