Validate User Input

For most programs, displaying data is only half of the battle. The other big challenge is analyzing, accepting, and rejecting data entered by the user. In an ideal world, where all users always enter logical and accurate data, this would be a simple task. In the real world, however, this is not at all the case.

It is our job, as developers and architects, to combat the inevitable erroneous and malicious input entered by our users. The WPF binding infrastructure has support for input validation. In the next few sections of this article, I'll examine how to make use of the WPF support for validation, as well as how to display validation error messages to the user.
Input Validation via ValidationRules

The Binding class has a validationRules’ property, which can store any number of ValidationRule-derived classes. Each of those rules can contain some logic that tests to see if the bound value is valid.

WPF only came with one ValidationRule subclass, called ExceptionValidationRule. Developers could add that rule to a binding's ValidationRules and it would catch exceptions thrown during updates made to the data source, allowing the UI to display the exception's error message. The usefulness of this approach to input validation is debatable, considering that the bedrock of good user experience is to avoid unnecessarily revealing technical details to the user. The error messages in data parsing exceptions are generally too technical for most users, but I digress.

Suppose that you have a class that represents an era of time, such as the simple Era class seen here:
public class Era : INotifyPropertyChanged
    {        
        // Declare the event
        public event PropertyChangedEventHandler PropertyChanged;

        public Era()
        {
        }

        private DateTime m_StartDate;
        public DateTime StartDate
        {
            get { return m_StartDate; }
            set
            {
                m_StartDate = value;
                // Call OnPropertyChanged whenever the property is updated
                OnPropertyChanged("StartDate");
            }
        }

        private TimeSpan m_Duration;
        public TimeSpan Duration 
        {
            get { return m_Duration; }
            set
            {
                m_Duration = value;
                // Call OnPropertyChanged whenever the property is updated
                OnPropertyChanged("Duration");
            }
        }

        // Create the OnPropertyChanged method to raise the event
        protected void OnPropertyChanged(string prop)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(prop));
            }
        }
    }

If you want to allow the user to edit the start date and duration of an era, you could use two textbox controls and bind their Text properties to the properties of an Era instance. Since the user could enter any text he wants into a textbox, you cannot be sure that the input text will be convertible to an instance of DateTime or TimeSpan. In this scenario, you can use the ExceptionValidationRule to report data conversion errors, and then display those conversion errors in the user interface. The XAML listed below demonstrates how to achieve this task.
     <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <!-- START DATE -->
        <TextBlock Grid.Row="0">Start Date:</TextBlock>
        <TextBox Grid.Row="1">
            <TextBox.Text>
                <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <ExceptionValidationRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <!-- DURATION -->
        <TextBlock Grid.Row="2">Duration:</TextBlock>
        <TextBox Grid.Row="3"
                 Text="{Binding Path=Duration, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}"/>
        
        <Button Grid.Row="4" Click="Button_Click">OK</Button>
    </Grid>

Those two textboxes demonstrate the two ways that an ExceptionValidationRule can be added to the ValidationRules of a binding in XAML. The Start Date textbox uses the verbose property-element syntax to explicitly add the rule. The Duration textbox uses the shorthand syntax by simply setting the ValidatesOnExceptions property of the binding to true. Both bindings have their UpdateSourceTrigger property set to PropertyChanged so that the input is validated every time the textbox's Text property is given a new value, instead of waiting until the control loses focus.
 
Figure 1 ExceptionValidationRule Displays Validation Errors

 

Displaying Validation Errors
As seen in Figure 1, the Duration textbox contains an invalid value. The string it contains is not convertible to a TimeSpan instance. The textbox's tooltip displays an error message, and a small red error icon appears on the right side of the control. This behavior does not happen automatically, but it is easy to implement and customize.

Render Input Validation Errors to the User

     <Window.Resources>
        <!--
        The template which renders a TextBox
        when it contains invalid data.
        -->
        <ControlTemplate x:Key="TextBoxErrorTemplate">
            <DockPanel>
                <Ellipse
                    DockPanel.Dock="Right" 
                    Margin="2,0"
                    ToolTip="Contains invalid data"
                    Width="10" Height="10"
                    >
                    <Ellipse.Fill>
                        <LinearGradientBrush>
                            <GradientStop Color="#11FF1111" Offset="0" />
                            <GradientStop Color="#FFFF0000" Offset="1" />
                        </LinearGradientBrush>
                    </Ellipse.Fill>
                </Ellipse>
                <!--
                This placeholder occupies where the TextBox will appear.
                -->
                <AdornedElementPlaceholder />
            </DockPanel>
        </ControlTemplate>

        <!--
        The Style applied to both TextBox controls in the UI.
        -->
        <Style TargetType="TextBox">
            <Setter Property="Margin" Value="4,4,10,4" />
            <Setter 
                Property="Validation.ErrorTemplate" 
                Value="{StaticResource TextBoxErrorTemplate}" 
                />
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="ToolTip">
                        <Setter.Value>
                            <Binding 
                                Path="(Validation.Errors)[0].ErrorContent"
                                RelativeSource="{x:Static RelativeSource.Self}"
                                />
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

The static Validation class forms a relationship between a control and any validation errors it contains by the use of some attached properties and static methods. You can reference those attached properties in XAML to create markup-only descriptions of how the user interface should present input validation errors to the user. The above XAML is responsible for explaining how to render input errors messages for the two textbox controls in the previous example.

The Style targets all instances of a textbox in the UI. It applies three settings to a textbox. The first Setter affects the textbox's Margin property. The Margin property is set to a value that provides enough space to display the error icon on the right side.
The next Setter in the Style assigns the ControlTemplate used to render the textbox when it contains invalid data. It sets the attached Validation.ErrorTemplate property to the Control­Template declared above the Style. When the Validation class reports that the textbox has one or more validation errors, the textbox renders with that template. This is where the red error icon comes from, as seen in Figure 1.
The Style also contains a Trigger that monitors the attached Validation.HasError property on the textbox. When the Validation class sets the attached HasError property to true for the textbox, the Style's Trigger activates and assigns a tooltip to the textbox. The content of the tooltip is bound to the error message of the exception thrown when attempting to parse the textbox's text into an instance of the source property's data type.

 

Input Validation via IDataErrorInfo
With the introduction of the Microsoft .NET Framework 3.5, WPF support for input validation vastly improved. The Validation­Rule approach is useful for simple applications, but real-world applications deal with the complexity of real-world data and business rules. Encoding business rules into Validation­Rule objects not only ties that code to the WPF platform, but it also does not allow for business logic to exist where it belongs: in business objects!
Many applications have a business layer, where the complexity of processing business rules is contained in a set of business objects. When compiling against the Microsoft .NET Framework 3.5, you can make use of the IDataErrorInfo interface to have WPF ask business objects if they are in a valid state or not. This removes the need to place business logic in objects separate from the business layer, and it allows you to create UI platform-independent business objects. Since the IDataErrorInfo interface has been around for years, this also makes it much easier to reuse business objects from a legacy Windows Forms or ASP.NET application.
Suppose that you need to provide validation for an era beyond just ensuring that the user's text input is convertible to the source property's data type. It might make sense that an era's start date cannot be in the future, since we do not know about eras that have yet to exist. It might also make sense to require that an era last for at least one millisecond.
These types of rules are similar to the generic idea of business logic in that they are both examples of domain rules. It is best to implement domain rules in the objects that store their state: domain objects. The code listed below shows the SmartEra class, which exposes validation error messages via the IData­ErrorInfo interface.

public class SmartEra : Era , IDataErrorInfo
    {
        #region IDataErrorInfo Members

        public string Error
        {
            get { return null; }
        }

        public string this[string property]
        {
            get
            {
                string msg = null;
                switch (property)
                {
                    case "StartDate":
                        if (DateTime.Now < this.StartDate)
                            msg = "Start date must be in the past.";
                        break;

                    case "Duration":
                        if (this.Duration.Ticks == 0)
                            msg = "An era must have a duration.";
                        break;

                    default:
                        throw new ArgumentException(
                            "Unrecognized property: " + property);
                }
                return msg;
            }
        }

        #endregion // IDataErrorInfo Members
    }


 Consuming the validation support of the SmartEra class from a WPF user interface is very simple. The only thing you have to do is tell the bindings that they should honor the IDataErrorInfo interface on the object to which they are bound. You can do this in one of two ways, as below:

<!-- START DATE -->
<TextBlock Grid.Row="0">Start Date:</TextBlock>
<TextBox Grid.Row="1">
  <TextBox.Text>
    <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged">
      <Binding.ValidationRules>
        <ExceptionValidationRule />
        <DataErrorValidationRule />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>

<!-- DURATION -->
<TextBlock Grid.Row="2">Duration:</TextBlock>
<TextBox 
  Grid.Row="3" 
  Text="{Binding 
         Path=Duration, 
         UpdateSourceTrigger=PropertyChanged, 
         ValidatesOnDataErrors=True,
         ValidatesOnExceptions=True}" 
 />
 
Similar to how you can add the ExceptionValidationRule explicitly or implicitly to a binding's ValidationRules collection, you can add the DataErrorValidationRule directly to the ValidationRules of a binding, or you can just set the ValidatesOnDataErrors property to true. Both approaches result in the same net effect; the binding system queries the data source's IDataErrorInfo interface for validation errors.


 

<think>首先,用户的问题是:“我想根据提供的代码生成流程图请问将给定的登录流程代码转换为可视化流程图”。但用户没有提供具体的代码。在之前的引用中,有提到一些代码片段,比如快速排序的Python代码,但用户说的是“登录流程代码”,所以这可能是一个误解。 回顾系统级指令:我必须使用中文回答,生成相关问题,并确保回答结构清晰。指令还指定了数学表达式的格式,但用户的问题是关于代码到流程图的转换。用户引用的内容:-引用[1]:提到将文本(如Markdown)转换为思维导图或流程图,使用工具如MarkMap、Mermaid、Draw.io等。 -引用[2]:关于SVG和Canvas,用于图形渲染。-引用[3]:描述数据处理和可视化,包括用户画像、时间序列预测等。 -引用[4]:涉及ISOMAP算法的代码。用户的问题是关于将登录流程代码转换为流程图。所以,我需要假设用户有登录流程代码,但未提供。我应该引导用户提供代码,或者基于常见登录流程给出一般性指导。在回答中,我必须: 1.使用中文。2.生成相关问题。3.回答结构清晰,逐步解决问题。4.添加引用标识在引用的段落末尾。5.确保LaTeX语法正确(但这里可能不涉及数学表达式)。 结构化的回答:-先解释如何将代码转换为流程图。-建议工具和方法。 -生成相关问题。-引用相关部分。从引用[1],关键点是使用工具如Mermaid、Draw.io来从文本生成流程图。引用中提到“文本→ Markdown →思维导图”,所以我可以建议使用类似方法。 步骤: 1. **理解代码逻辑**:分析登录流程代码,提取关键步骤(如输入用户名、验证密码等)。 2. **选择工具**:推荐使用Mermaid(因为它在Markdown中支持流程图)或Draw.io。 3. **创建流程图**:描述如何用Mermaid语法编写流程图。4.**可视化**:解释如何渲染或导出。 示例:如果用户提供代码,我可以转换,但既然没有,我就给出一般方法。生成相关问题:-基于用户问题,如如何优化流程图、工具推荐等。 引用:在回答中,如果提到引用内容,在末尾添加[^n]。最终回答结构: -介绍方法。 -步骤指南。 -工具推荐。-相关问题。</think>### 将登录流程代码转换为可视化流程图 要将给定的登录流程代码转换为可视化流程图,您需要遵循一个清晰的步骤:首先理解代码逻辑,然后选择合适的工具生成流程图,最后进行可视化渲染。以下是基于最佳实践的详细指南(假设您已有登录流程代码,如Python或其他语言的实现)。我将以常见登录流程为例说明(例如基于用户名和密码验证),但您可以根据实际代码调整。 #### 步骤1: 分析代码逻辑并提取关键步骤 登录流程代码通常包含以下核心步骤(以伪代码表示): - 用户输入用户名和密码。 - 系统验证输入是否有效(如非空检查)。 - 查询数据库验证凭据。 - 根据验证结果跳转(成功则进入主页,失败则提示错误)。 - 可选步骤:日志记录、会话管理等。 例如,一个简单的Python登录代码片段可能如下: ```python def login(username, password): if not username or not password: # 输入验证 return "输入不能为空" if check_database(username, password): # 数据库查询 create_session(username) # 创建会话 return "登录成功" else: return "用户名或密码错误" ``` 要转换为流程图,需将这些步骤抽象为节点(如开始、输入、判断、结束)。 #### 步骤2: 使用工具生成流程图 推荐使用以下工具,它们支持从文本描述(如Markdown或专用语法)自动生成流程图,高效且可定制。基于引用[1],主流方法包括: - **Mermaid + Draw.io**:Mermaid 是一个基于Markdown的流程图生成库,语法简洁;Draw.io 提供图形化界面,支持自定义样式和导出为SVG/PNG。Mermaid 适用于快速生成,Draw.io 适合精细调整[^1]。 - **Markdown + MarkMap**:如果您的流程图较简单(如思维导图风格),可以用Markdown编写,再通过MarkMap工具转换为交互式流程图[^1]。 - 其他选项:如PlantUML(适合复杂流程),但Mermaid和Draw.io更易上手。 **示例:用Mermaid语法转换登录流程** 假设基于上述代码,流程图可以用Mermaid描述如下(保存为.mmd文件或在支持Mermaid的编辑器中使用): ```mermaid graph TD A[开始] --> B[输入用户名和密码] B --> C{输入是否有效?} C -- 是 --> D[查询数据库验证] C -- 否 --> E[提示输入错误] D --> F{验证成功?} F -- 是 --> G[创建会话并跳转主页] F -- 否 --> H[提示用户名或密码错误] G --> I[结束] H --> I ``` - **如何可视化**: - 在线工具:粘贴代码到 [Mermaid Live Editor](https://mermaid.live/) 或 [Draw.io](https://app.diagrams.net/),即可实时渲染为流程图。 - 本地工具:安装VS Code插件(如Mermaid Preview),或使用Python库(如`mermaid`包)生成SVG文件。SVG格式可缩放且清晰,适合嵌入网页[^2]。 - **优势**:这种方法避免了手动绘图,可直接从代码逻辑导出,减少错误。 #### 步骤3: 优化和导出 - **自定义样式**:在Draw.io中,您可以调整节点颜色、字体大小等,使流程图更直观(例如,用绿色表示成功路径,红色表示错误路径)。 - **导出格式**:推荐导出为SVG(矢量图,放大不失真)或PNG(便于分享)。SVG基于XML,易于嵌入Web应用[^2]。 - **验证流程图**:确保流程图与代码逻辑一致,例如添加循环处理(如重试机制)或分支(如多因素认证)。 如果您的登录流程涉及更复杂逻辑(如引用[3]中的用户画像或时间序列预测),可以结合数据处理步骤扩展流程图[^3]。或者,如果代码包含算法(如引用[4]的ISOMAP降维),流程图可包括计算节点[^4]。 #### 注意事项 - **代码要求**:您需要提供具体的登录流程代码(如Python、Java等),我才能生成精确的Mermaid或Draw.io语法。如果上传代码,我可以协助转换。 - **工具选择**:对于简单流程,Mermaid足够;对于企业级应用,Draw.io更专业。所有工具均免费开源。 - **常见问题**:如果流程图不渲染,检查语法错误(如节点连接符是否正确)。 通过以上步骤,您可以将任何登录代码高效转换为可视化流程图,提升代码可读性和文档质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值