WPF自验证控制
本文关键字:控制 验证 WPF | 更新日期: 2023-09-27 17:57:59
我必须构建一个自定义控件。带有内置验证的简单文本框,我可以在应用程序的不同部分使用。我是这样做的:
- 我创建了直接从TextBox派生的新自定义控件(称之为ValidTextBox)
- 它有一个带有简单验证逻辑的视图模型(ValidTextBoxVM)
- 控件的Text属性绑定到视图模型的Number属性
ValidTextBoxVM代码:
public class ValidTextBoxVM : INotifyPropertyChanged
{
#region INotifyPropertyChange implementation
private String _number;
public String Number
{
get { return _number; }
set
{
if (_number != value)
{
Validate(value);
_number = value;
RaisePropertyChanged("Number");
}
}
}
private void Validate(string number)
{
if (!string.IsNullOrEmpty(number) && number.Length > 10)
{
throw new ArgumentOutOfRangeException("Number too long.");
}
}
}
ValidTextBox.xaml代码:
<TextBox x:Class="WpfApplication1.ValidTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:WpfApplication1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Text="{Binding Number, ValidatesOnExceptions=True, UpdateSourceTrigger=LostFocus}">
<TextBox.DataContext>
<vm:ValidTextBoxVM/>
</TextBox.DataContext>
</TextBox>
我把控制权放在MainWindow上,它运行得很好。在失去焦点时,如果验证过程没有通过,ViewModel会引发异常——这没关系(下面的代码)。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:WpfApplication1"
xmlns:vm="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ctrl:ValidTextBox Margin="5" Width="200" HorizontalAlignment="Left"/>
</StackPanel>
</Window>
当我为MainWindow(MainWindowVM)使用单独的视图模型并将控件的Text属性与MainWindowVM中的字段(MainNumber)绑定时,情况发生了变化。它隐藏了我以前的绑定,验证已经停止工作(下面的代码)。
<StackPanel>
<ctrl:ValidTextBox Text="{Binding MainNumber, ValidatesOnExceptions=True, UpdateSourceTrigger=LostFocus}" Margin="5" Width="200" HorizontalAlignment="Left"/>
</StackPanel>
是否有任何模式可以使创建自验证控件成为可能。我发现了许多解决方案,但验证过程超出了控制范围。
问题是在TextBox
上设置DataContext
。这意味着当你写:
<ctrl:ValidTextBox Text="{Binding MainNumber
框架将尝试解析ctrl:ValidTextBox
对象上的"MainNumber",即对象的DataContext。(这是违反直觉的,但它就是这样工作的——如果您检查Visual Studio"Output"窗口,您应该能够看到对象"ValidTextBox"上"找不到属性"MainNumber"的绑定错误。)
我发现,使用特定于控件的视图模型通常很棘手,并且会导致复杂性。我建议尽可能避免这种做法。在这种情况下,为什么不扩展TextBox
并为LostFocus
事件添加一个验证处理程序呢?
public class ValidTextBox : TextBox
{
public ValidTextBox()
{
LostFocus += ValidTextBox_LostFocus;
}
void ValidTextBox_LostFocus(object sender, System.Windows.RoutedEventArgs e)
{
// TODO validate
}
}