七月 15, 2009

在WPF对话框中如何验证用户提供的数据

Written by

     在WPF中,MS在msdn的WPF应用程序开发中对用户输入的数据验证做了示范,基本思想就是添加各种类型的校验规则,比如最大最小值、字符串长度、是否为空等等,在后在界面绑定数据时添加数据字段的校验。这样基本没什么大问题,就是在绑定时需要重复添加数据校验规则,非常费事。csla基本继承了这种思想,只不过把校验规则写成了静态类,在所有business object中重用。同时business object自己实现了IDataError接口,维护校验结果;实现了IBindable接口,自动实现绑定校验,从而不需要在界面绑定时重写绑定校验规则,提高了产出效率。

     下面文章来自msdn,竟然在“对话框概述”里面,让我好找:

     msdn->.NET 开发->.NET Framework SDK->.NET Framework->Windows Presentation Foundation->应用程序开发->WPF 窗口->对话框概述

 

验证用户提供的数据

在打开对话框以及用户提供所需的数据时,对话框负责确保提供的数据有效,原因如下:

  • 从安全角度讲,应验证所有输入。

  • 从特定于域的角度讲,数据验证可防止该代码处理错误的数据,因为这样可能会引发异常。

  • 从用户体验的角度讲,对话框可以通过向用户显示哪些输入数据无效来为用户提供帮助。

  • 从性能角度讲,多层应用程序中的数据验证可以减少客户端和应用程序层之间的往返次数,尤其是在该应用程序由 Web 服务或基于服务器的数据库组成时。

若要验证 WPF 中的绑定控件,您需要定义验证规则,然后将其与该绑定关联。验证规则是派生自 ValidationRule 的自定义类。下面的示例演示验证规则 MarginValidationRule,该规则检查绑定值是否是 Double 以及是否位于指定的范围内。

C# 

using System.Globalization;
using System.Windows.Controls;

namespace SDKSample
{
    public class MarginValidationRule : ValidationRule
    {
        double minMargin;
        double maxMargin;

        public double MinMargin
        {
            get { return this.minMargin; }
            set { this.minMargin = value; }
        }

        public double MaxMargin
        {
            get { return this.maxMargin; }
            set { this.maxMargin = value; }
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            double margin;

            // Is a number?
            if (!double.TryParse((string)value, out margin))
            {
                return new ValidationResult(false, "Not a number.");
            }

            // Is in range?
            if ((margin < this.minMargin) || (margin > this.maxMargin))
            {
                string msg = string.Format("Margin must be between {0} and {1}.", this.minMargin, this.maxMargin);
                return new ValidationResult(false, msg);
            }

            // Number is valid
            return new ValidationResult(true, null);
        }
    }
}

Visual Basic 

Imports System.Globalization
Imports System.Windows.Controls

Namespace SDKSample

Public Class MarginValidationRule
    Inherits ValidationRule

    Private _maxMargin As Double
    Private _minMargin As Double

    Public Property MaxMargin() As Double
        Get
            Return Me._maxMargin
        End Get
        Set(ByVal value As Double)
            Me._maxMargin = value
        End Set
    End Property

    Public Property MinMargin() As Double
        Get
            Return Me._minMargin
        End Get
        Set(ByVal value As Double)
            Me._minMargin = value
        End Set
    End Property

    Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As CultureInfo) As ValidationResult

        Dim margin As Double

        ' Is a number?
        If Not Double.TryParse(CStr(value), margin) Then
            Return New ValidationResult(False, "Not a number.")
        End If

        ' Is in range?
        If ((margin < Me.MinMargin) OrElse (margin > Me.MaxMargin)) Then
            Dim msg As String = String.Format("Margin must be between {0} and {1}.", Me.MinMargin, Me.MaxMargin)
            Return New ValidationResult(False, msg)
        End If

        ' Number is valid
        Return New ValidationResult(True, Nothing)

    End Function

End Class

End Namespace

在此代码中,通过重写 Validate 方法来实现验证规则的验证逻辑,该方法对数据进行验证并返回相应的 ValidationResult

若要将验证规则与绑定控件关联,您需要使用以下标记。

XAML 

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.MarginsDialogBox"
    xmlns:local="clr-namespace:SDKSample"
    Title="Margins"
    Height="190"
    Width="300"
    MinHeight="10"
    MinWidth="300"
    ResizeMode="CanResizeWithGrip"
    ShowInTaskbar="False"
    WindowStartupLocation="CenterOwner" 
    FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">

  <Grid>



...


<Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
<TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0">
  <TextBox.Text>
    <Binding Path="Left" UpdateSourceTrigger="PropertyChanged">
      <Binding.ValidationRules>
        <local:MarginValidationRule MinMargin="0" MaxMargin="10" />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>


...


</Window>

对验证规则进行关联之后,WPF 将在数据输入绑定控件时自动应用该规则。如果控件包含无效的数据,则 WPF 将在无效控件周围显示一个红色边框,如下图所示。

 

在用户输入有效数据之前,WPF 不会将用户限制于无效的控件。这对于对话框来说是很有利的;无论数据是否有效,用户都应当能够在对话框中自由导航控件。但是,这意味着用户可以输入无效的数据,然后按“确定”按钮。因此,在按“确定”按钮时,您的代码还需要通过处理 Click 事件来验证对话框中的所有控件。

C# 

using System.Windows; // Window, RoutedEventArgs, IInputElement, DependencyObject
using System.Windows.Controls; // Validation
using System.Windows.Input; // Keyboard

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {


...


void okButton_Click(object sender, RoutedEventArgs e)
{
    // Don't accept the dialog box if there is invalid data
    if (!IsValid(this)) return;


...


        }

        // Validate all dependency objects in a window
        bool IsValid(DependencyObject node)
        {
            // Check if dependency object was passed
            if (node != null)
            {
                // Check if dependency object is valid.
                // NOTE: Validation.GetHasError works for controls that have validation rules attached 
                bool isValid = !Validation.GetHasError(node);
                if (!isValid)
                {
                    // If the dependency object is invalid, and it can receive the focus,
                    // set the focus
                    if (node is IInputElement) Keyboard.Focus((IInputElement)node);
                    return false;
                }
            }

            // If this dependency object is valid, check all child dependency objects
            foreach (object subnode in LogicalTreeHelper.GetChildren(node))
            {
                if (subnode is DependencyObject)
                {   
                    // If a child dependency object is invalid, return false immediately,
                    // otherwise keep checking
                    if (IsValid((DependencyObject)subnode) == false) return false;
                }
            }

            // All dependency objects are valid
            return true;
        }
    }
}

Visual Basic 

Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard

Namespace SDKSample


Public Class MarginsDialogBox
    Inherits Window


...


Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    ' Don't accept the dialog box if there is invalid data
    If Not Me.IsValid(Me) Then Return


...


    End Sub

    ' Validate all dependency objects in a window
    Private Function IsValid(ByVal node As DependencyObject) As Boolean

        ' Check if dependency object was passed and if dependency object is valid.
        ' NOTE: Validation.GetHasError works for controls that have validation rules attached 
        If ((Not node Is Nothing) AndAlso Validation.GetHasError(node)) Then
            ' If the dependency object is invalid, and it can receive the focus,
            ' set the focus
            If TypeOf node Is IInputElement Then
                Keyboard.Focus(DirectCast(node, IInputElement))
            End If
            Return False
        End If

        ' If this dependency object is valid, check all child dependency objects
        Dim subnode As Object
        For Each subnode In LogicalTreeHelper.GetChildren(node)
            If (TypeOf subnode Is DependencyObject AndAlso Not Me.IsValid(DirectCast(subnode, DependencyObject))) Then
                ' If a child dependency object is invalid, return false immediately,
                ' otherwise keep checking
                Return False
            End If
        Next

        ' All dependency objects are valid
        Return True

    End Function

End Class

End Namespace

此代码将在窗口上枚举所有依赖项对象。如果有任何一个对象无效(由 GetHasError 返回),则此无效的控件将获得焦点,IsValid 方法将返回 false 并将该窗口视为无效。

一旦对话框有效,则可以安全地关闭并返回。在返回过程中,需要向调用函数返回一个结果。

 

Category : .NetC#Window$WPF其他

Tags :

发表评论

电子邮件地址不会被公开。

Proudly powered by WordPress and Sweet Tech Theme