WPF自我验证控件

时间:2014-04-11 15:25:19

标签: c# wpf validation mvvm custom-controls

我必须构建一个自定义控件。简单的TextBox内置验证,我可以在我的应用程序的不同部分使用。 我是这样做的:

  1. 我创建了直接从TextBox;
  2. 派生的新自定义控件(称之为ValidTextBox)
  3. 它的viewmodel(ValidTextBoxVM)具有简单的验证逻辑。
  4. 控件的Text属性绑定到viewmodel的Number属性。
  5. 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)使用单独的viewmodel并将我的控件的Text属性与MainWindowVM中的field(MainNumber)绑定时,情况发生了变化。 它隐藏了我以前的绑定和验证已经停止工作(下面的代码)。

    <StackPanel>
        <ctrl:ValidTextBox Text="{Binding MainNumber, ValidatesOnExceptions=True, UpdateSourceTrigger=LostFocus}" Margin="5" Width="200" HorizontalAlignment="Left"/>
    </StackPanel>
    

    是否有任何模式可以创建自我验证控件。我找到了许多解决方案,但验证过程不受控制。

1 个答案:

答案 0 :(得分:1)

问题是在DataContext上设置了TextBox。这意味着当你写:

<ctrl:ValidTextBox Text="{Binding MainNumber

...框架将尝试解析ctrl:ValidTextBox对象上的“MainNumber”,该对象是对象的DataContext。 (这是违反直觉的,但这就是它的工作原理 - 如果检查Visual Studio“输出”,你应该能够在对象“ValidTextBox”上找到“无法找到属性”MainNumber“的绑定错误”窗口。)


我发现使用特定于控件的视图模型通常很棘手,并且会导致并发症。我建议尽可能避免这种做法。在这种情况下,为什么不只是扩展TextBox并为LostFocus事件添加验证处理程序?

public class ValidTextBox : TextBox
{
    public ValidTextBox()
    {
        LostFocus += ValidTextBox_LostFocus;
    }

    void ValidTextBox_LostFocus(object sender, System.Windows.RoutedEventArgs e)
    {
        // TODO validate
    }
}