如果绑定一个整数属性,输入非整数会反馈错误(比如红框,或自己设计一个别的)。
不想得到突兀的反馈,先想到的方法:
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万+

被折叠的 条评论
为什么被折叠?



