WPF绑定属性时的输入验证新思路

如果绑定一个整数属性,输入非整数会反馈错误(比如红框,或自己设计一个别的)。
不想得到突兀的反馈,先想到的方法:
1、事前验证:限制输入字符,通过PreviewKeyDown事件过滤字符,但无法拦截粘贴内容。WPF的TextBox也没有类似PreviewPaste的事件.
2、事中验证:在TextChanged事件里,检查输入后的内容是否合规,不合规则删除新输入的部分。这要保存前值,保存光标位置,判断各种情况,有点复杂。
最终想到一个事后验证的解决办法,在数据接收端来验证。
错误格式在ViewModel部分被无差别接收,检验正确,传给Model,检验错误,View端变回原值。为此,把ViewModel的属性全部设计成String.

<Window x:Class="MyValidation.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyValidation"
        mc:Ignorable="d"
        Title="MainWindow" Height="100" Width="400" >
    <Grid>
        <TextBox x:Name="focusHolder" Width="0"/>
        <WrapPanel Margin="10" VerticalAlignment="Center">
            <TextBlock Text="年龄: "/>
            <TextBox Width="100" Text="{Binding Age}" PreviewMouseDown="TextBox_PreviewMouseDown" PreviewKeyDown="TextBox_PreviewKeyDown"/>
            <TextBlock Text="{Binding Age}" Width="50"/>
            <TextBox Width="100" Text="{Binding Name}" PreviewMouseDown="TextBox_PreviewMouseDown" PreviewKeyDown="TextBox_PreviewKeyDown"/>
            <TextBlock Text="{Binding Name}" Width="50"/>
        </WrapPanel>
    </Grid>
</Window>
using System.ComponentModel;
using System.Diagnostics;
using System.Net.Cache;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace MyValidation
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();
            DataContext = new Student_View();
        }


        private void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            TextBox textBox = sender as TextBox;
            if(!textBox.IsFocused)
            {
                // 假如不在焦点,点击选择全部,便于编辑。
                textBox.Focus();
                textBox.SelectAll();
                e.Handled = true;  // 不再继续处理鼠标动作,避免把焦点消除。
            }
        }

        private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            // 回车键,提交数据,并选中全部。
            // 由于默认是失去焦点提交数据,要实现回车失去焦点再返回焦点。
            TextBox textBox = sender as TextBox;
            if(e.Key == Key.Enter)
            {
                focusHolder.Focus(); // 移除输入焦点, focusHolder为一个宽度为0的textbox, 用于暂存焦点.
                textBox.Focus(); // 返回焦点
                textBox.SelectAll();
            }
        }
    }

    class Student_View : INotifyPropertyChanged
    {
        // 数据源
        private Student student = new() { Name = "Tom", Age=19 };

        // 所有与前端绑定的属性,全部用String,避免前端出现输入格式错误警告。
        // 接受数据后再检查转换,如果格式不对,则返回先前数据。
        public String? Name 
        {
            get { return student.Name; }
            set
            {
                string str = value.Trim(); //消除空格
                if(str.Length != 0)
                {
                    // 假如不空,则提交数据
                    student.Name = str;
                }
                
                NotifyChange("Name"); // 提醒前端更新
            }
        }
        public String Age 
        {
            get{return student.Age.ToString();}
            set 
            {
                int num;
                // 判断字符串是否为整数,如果是,则提交,否则,不变。
                bool success = int.TryParse(value, out num);
                if(success)
                {
                    student.Age = num;
                }
                NotifyChange("Age");
            }
        }

        // 通知属性更新函数,函数简化,方便调用。
        public event PropertyChangedEventHandler? PropertyChanged;
        private void NotifyChange(String PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }

    }
    class Student
    {
        public String? Name { get; set; }
        public int Age { get; set; }
    }

}


 





 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值