WPF TextBox 添加范围验证

WPF TextBox 添加范围验证

添加范围验证,若出现范围错误添加信息捕捉
使用到技术:使用ValidationRules实现范围验证,当范围出现错误时,可以通过触发器Validation.HasError=True设置自定义错误样式。
使用Behavior技术捕捉所有验证出错的消息,用于检查界面是否出错,实现行为捕获。
Behavior使用NuGet获取Microsoft.Xaml.Behaviors.Wpf
Mvvm使用NuGet获取CommunityToolkit.Mvvm
DI使用NuGet获取Microsoft.Extensions.DependencyInjection
界面库NuGet获取WeDraft.Toolkit.FirstDraft

第一步:正常MVVM模式定义View和ViewModel

View

<UserControl x:Class="Forwarding.Views.One2ManyView"
             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:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Forwarding.Views"
             mc:Ignorable="d" 
             DataContext="{Binding One2Many, Source={StaticResource Locator}}"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid Margin="20">
        <StackPanel>
            <TextBlock Text="0~10000以内的加法(a和b的取值范围在[0,10000])" />
            <WrapPanel Margin="0 5">
                <TextBlock Text="a:" Width="50" TextAlignment="Right"/>
                <TextBox Text="{Binding Param1}" MinWidth="50" TextAlignment="Right"/>
            </WrapPanel>
            <WrapPanel>
                <TextBlock Text="b:" Width="50" TextAlignment="Right"/>
                <TextBox Text="{Binding Param2}" MinWidth="50" TextAlignment="Right"/>
            </WrapPanel>
            <Border HorizontalAlignment="Stretch" Height="1" Background="Brown" Margin="0 5"/>
            <WrapPanel>
                <Button Content="a+b="  Width="50" Command="{Binding CalCommand}"/>
                <TextBox Text="{Binding Result}" MinWidth="50" TextAlignment="Right"/>
            </WrapPanel>
        </StackPanel>
    </Grid>
</UserControl>

ViewModel

public class One2ManyViewModel : ObservableObject
    {
        private int param2;

        public int Param2
        {
            get { return param2; }
            set { SetProperty(ref param2, value); }
        }

        private int param1;

        public int Param1
        {
            get { return param1; }
            set { SetProperty(ref param1, value); }
        }

        private int result;

        public int Result
        {
            get { return result; }
            set { SetProperty(ref result, value); }
        }

        public RelayCommand CalCommand => new RelayCommand(() =>
        {
            Result = Param1 + Param2;
        });
    }

在这里插入图片描述

DI

App.xaml

<Application x:Class="Forwarding.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Forwarding"
             xmlns:di="clr-namespace:Forwarding.Data"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/FirstDraft;component/Themes/Ui.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <di:ServiceLocator x:Key="Locator"/>
        </ResourceDictionary>
    </Application.Resources>
</Application>

App.xaml.cs

  /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public App()
        {
            Services = ConfigureServices();

            this.InitializeComponent();
        }

        /// <summary>
        /// Gets the current <see cref="App"/> instance in use
        /// </summary>
        public new static App Current => (App)Application.Current;

        /// <summary>
        /// Gets the <see cref="IServiceProvider"/> instance to resolve application services.
        /// </summary>
        public IServiceProvider Services { get; }

        /// <summary>
        /// Configures the services for the application.
        /// </summary>
        private static IServiceProvider ConfigureServices()
        {
            var services = new ServiceCollection();
            
            services.AddSingleton<One2ManyViewModel>();

            return services.BuildServiceProvider();
        }
    }

ServiceLocator

    internal class ServiceLocator
    {
        public One2ManyViewModel One2Many => App.Current.Services.GetService<One2ManyViewModel>();
    }

第二步 添加最大最小值范围验证

定义范围验证类

 public class RangeValidationRule : ValidationRule
    {
        private int min;
        private int max;

        public int Min
        {
            get { return min; }
            set { min = value; }
        }

        public int Max
        {
            get { return max; }
            set { max = value; }
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            int val = 0;
            var strVal = (string)value;
            try
            {
                if (strVal.Length > 0)
                {
                    if (strVal.EndsWith("."))
                    {
                        return CheckRanges(strVal.Replace(".", ""));
                    }

                    // Allow dot character to move to next box
                    return CheckRanges(strVal);
                }
            }
            catch (Exception e)
            {
                return new ValidationResult(false, "Illegal characters or " + e.Message);
            }

            if ((val < Min) || (val > Max))
            {
                return new ValidationResult(false,
                  "Please enter the value in the range: " + Min + " - " + Max + ".");
            }
            else
            {
                return ValidationResult.ValidResult;
            }
        }

        private ValidationResult CheckRanges(string strVal)
        {
            if (int.TryParse(strVal, out var res))
            {
                if ((res < Min) || (res > Max))
                {
                    return new ValidationResult(false,
                      "Please enter the value in the range: " + Min + " - " + Max + ".");
                }
                else
                {
                    return ValidationResult.ValidResult;
                }
            }
            else
            {
                return new ValidationResult(false, "Illegal characters entered");
            }
        }
    }

TextBox使用范围验证

                <TextBox MinWidth="50" TextAlignment="Right">
                    <TextBox.Text>
                        <Binding Path="Param1" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged">
                            <Binding.ValidationRules>
                                <local:RangeValidationRule  Min="0" Max="10000"/>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>

定义TextBox错误时界面显示

        <Style TargetType="TextBox">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <DockPanel>
                            <TextBlock Margin="1,2"
                                       DockPanel.Dock="Right"
                                       FontWeight="Bold"
                                       Foreground="Red"
                                       Text="" />
                            <AdornedElementPlaceholder />
                        </DockPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Trigger.Setters>
                        <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
                        <Setter Property="BorderBrush" Value="Red" />
                        <Setter Property="Background" Value="Red" />
                    </Trigger.Setters>
                </Trigger>
            </Style.Triggers>
        </Style>

添加验证后的View

<UserControl x:Class="Forwarding.Views.One2ManyView"
             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:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Forwarding.Views"
             mc:Ignorable="d" 
             DataContext="{Binding One2Many, Source={StaticResource Locator}}"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>

        <Style TargetType="TextBox">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <DockPanel>
                            <TextBlock Margin="1,2"
                                       DockPanel.Dock="Right"
                                       FontSize="14"
                                       FontWeight="Bold"
                                       Foreground="Red"
                                       Text="" />
                            <AdornedElementPlaceholder />
                        </DockPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Trigger.Setters>
                        <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
                        <Setter Property="BorderBrush" Value="Red" />
                        <Setter Property="Background" Value="Red" />
                    </Trigger.Setters>
                </Trigger>
            </Style.Triggers>
        </Style>

    </UserControl.Resources>
    <Grid Margin="20">
        <StackPanel>
            <TextBlock Text="0~10000以内的加法(a和b的取值范围在[0,10000])" />
            <WrapPanel Margin="0 5">
                <TextBlock Text="a:" Width="50" TextAlignment="Right"/>
                <TextBox MinWidth="50" TextAlignment="Right">
                    <TextBox.Text>
                        <Binding Path="Param1" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged">
                            <Binding.ValidationRules>
                                <local:RangeValidationRule  Min="0" Max="10000"/>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>
            </WrapPanel>
            <WrapPanel>
                <TextBlock Text="b:" Width="50" TextAlignment="Right"/>
                <TextBox MinWidth="50" TextAlignment="Right">
                    <TextBox.Text>
                        <Binding Path="Param2" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged">
                            <Binding.ValidationRules>
                                <local:RangeValidationRule  Min="0" Max="10000"/>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>
            </WrapPanel>
            <Border HorizontalAlignment="Stretch" Height="1" Background="Brown" Margin="0 5"/>
            <WrapPanel>
                <Button Content="a+b="  Width="50" Command="{Binding CalCommand}"/>
                <TextBox Text="{Binding Result}" MinWidth="50" TextAlignment="Right"/>
            </WrapPanel>
        </StackPanel>
    </Grid>
</UserControl>

在这里插入图片描述

第三步 引入Behavior对错误进行捕捉

NuGet 引用 项目 Microsoft.Xaml.Behaviors.Wpf

定义行为捕捉类

    public interface ITextValidationError
    {
        ObservableCollection<string> Errors { get; set; }
    }

    public class TextValidationErrorBehavior : Behavior<FrameworkElement>
    {
        protected override void OnAttached()
        {
            // 事件监听
            this.AssociatedObject.AddHandler(Validation.ErrorEvent, new EventHandler<ValidationErrorEventArgs>(OnValidationError));
        }

        private void OnValidationError(Object sender, ValidationErrorEventArgs e)
        {
            if (AssociatedObject.DataContext is ITextValidationError mainModel)
            {
                // 表示新产生的行为
                if (e.Action == ValidationErrorEventAction.Added)
                {
                    mainModel.Errors.Add(e.Error.ErrorContent.ToString());
                }
                else if (e.Action == ValidationErrorEventAction.Removed) // 该行为被移除,即代表验证通过
                {
                    mainModel.Errors.Remove(e.Error.ErrorContent.ToString());
                }
            }
        }

        protected override void OnDetaching()
        {
            // 移除事件监听
            this.AssociatedObject.RemoveHandler(Validation.ErrorEvent, new EventHandler<ValidationErrorEventArgs>(OnValidationError));
        }
    }

注意:接口ITextValidationError用于定义ViewModel获取错误消息的接口,示例使用DataContext进行传递。

ViewModel中对ITextValidationError接口实现并捕获错误

    public class One2ManyViewModel : ObservableObject, ITextValidationError
    {
        private int param2;

        public int Param2
        {
            get { return param2; }
            set { SetProperty(ref param2, value); }
        }

        private int param1;

        public int Param1
        {
            get { return param1; }
            set { SetProperty(ref param1, value); }
        }

        private int result;

        public int Result
        {
            get { return result; }
            set { SetProperty(ref result, value); }
        }

        private string errorMsg = string.Empty;

        public string ErrorMsg
        {
            get { return errorMsg; }
            set { SetProperty(ref errorMsg, value); }
        }

        public RelayCommand CalCommand => new RelayCommand(() =>
        {
            ErrorMsg = "";
            if (Errors.Count > 0)
            {
                ErrorMsg = "参数错误,原因:" + Errors[0];
                return;
            }
            Result = Param1 + Param2;
        });

        public ObservableCollection<string> Errors { get; set; } = new ObservableCollection<string>();
    }

View中添加使用行为捕捉

引入命名空间:xmlns:b=“http://schemas.microsoft.com/xaml/behaviors”
使用行为

    <b:Interaction.Behaviors>
        <local:TextValidationErrorBehavior />
    </b:Interaction.Behaviors>

View完整代码

<UserControl x:Class="Forwarding.Views.One2ManyView"
             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:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Forwarding.Views"
             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
             mc:Ignorable="d" 
             DataContext="{Binding One2Many, Source={StaticResource Locator}}"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>

        <Style TargetType="TextBox">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <DockPanel>
                            <TextBlock Margin="1,2"
                                       DockPanel.Dock="Right"
                                       FontSize="14"
                                       FontWeight="Bold"
                                       Foreground="Red"
                                       Text="" />
                            <AdornedElementPlaceholder />
                        </DockPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Trigger.Setters>
                        <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
                        <Setter Property="BorderBrush" Value="Red" />
                        <Setter Property="Background" Value="Red" />
                    </Trigger.Setters>
                </Trigger>
            </Style.Triggers>
        </Style>

    </UserControl.Resources>
    <b:Interaction.Behaviors>
        <local:TextValidationErrorBehavior />
    </b:Interaction.Behaviors>
    <Grid Margin="20">
        <StackPanel>
            <TextBlock Text="0~10000以内的加法(a和b的取值范围在[0,10000])" />
            <WrapPanel Margin="0 5">
                <TextBlock Text="a:" Width="50" TextAlignment="Right"/>
                <TextBox MinWidth="50" TextAlignment="Right">
                    <TextBox.Text>
                        <Binding Path="Param1" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged">
                            <Binding.ValidationRules>
                                <local:RangeValidationRule  Min="0" Max="10000"/>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>
            </WrapPanel>
            <WrapPanel>
                <TextBlock Text="b:" Width="50" TextAlignment="Right"/>
                <TextBox MinWidth="50" TextAlignment="Right">
                    <TextBox.Text>
                        <Binding Path="Param2" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged">
                            <Binding.ValidationRules>
                                <local:RangeValidationRule  Min="0" Max="10000"/>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>
            </WrapPanel>
            <Border HorizontalAlignment="Stretch" Height="1" Background="Brown" Margin="0 5"/>
            <WrapPanel>
                <Button Content="a+b="  Width="50" Command="{Binding CalCommand}"/>
                <TextBox Text="{Binding Result}" MinWidth="50" TextAlignment="Right"/>
                <TextBlock Text="{Binding ErrorMsg}" Foreground="Red"/>
            </WrapPanel>
        </StackPanel>
    </Grid>
</UserControl>

在这里插入图片描述


积跬步以至千里:) (:一阵没来由的风

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF 登录验证方式中,滑动拼图是一种常见的实现方式,通常被用于防止机器人或者恶意攻击。 实现滑动拼图的基本思路如下: 1. 在登录页面上添加一个滑块组件,包含一个滑块和一个拼图区域。 2. 当用户登录时,需要先通过输入用户名和密码进行身份验证验证通过后,显示滑块组件。 3. 用户需要按住滑块,将其拖动到正确的位置,使得拼图区域中的图片与滑块上的图片完全重合。 4. 当滑块被拖动到正确的位置时,将用户的登录信息提交给服务器进行验证。 下面是实现滑动拼图的示例代码: ```xml <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!-- 用户名和密码输入框 --> <StackPanel Grid.Row="0"> <TextBox Name="txtUsername" Margin="10" Width="200" PlaceholderText="Enter username"/> <PasswordBox Name="txtPassword" Margin="10" Width="200" PlaceholderText="Enter password"/> <Button Name="btnLogin" Content="Login" Click="btnLogin_Click" Margin="10"/> </StackPanel> <!-- 滑块组件 --> <Grid Grid.Row="1" Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <!-- 拼图区域 --> <Image Name="imgPuzzle" Stretch="Fill" Source="puzzle.jpg" Grid.Column="0"/> <!-- 滑块 --> <Canvas Name="canvasSlider" Width="100" Height="100" Grid.Column="1"> <Image Name="imgSlider" Stretch="Fill" Source="slider.jpg"/> </Canvas> </Grid> </Grid> ``` ```csharp private bool _isSliding; private Point _startPoint; private void canvasSlider_PointerPressed(object sender, PointerRoutedEventArgs e) { _isSliding = true; _startPoint = e.GetCurrentPoint(canvasSlider).Position; } private void canvasSlider_PointerMoved(object sender, PointerRoutedEventArgs e) { if (_isSliding) { Point currentPoint = e.GetCurrentPoint(canvasSlider).Position; double distance = currentPoint.X - _startPoint.X; if (distance >= 0 && distance <= imgPuzzle.ActualWidth - canvasSlider.ActualWidth) { Canvas.SetLeft(canvasSlider, distance); } } } private void canvasSlider_PointerReleased(object sender, PointerRoutedEventArgs e) { _isSliding = false; if (Canvas.GetLeft(canvasSlider) == imgPuzzle.ActualWidth - canvasSlider.ActualWidth) { // 验证通过,提交登录信息 string username = txtUsername.Text; string password = txtPassword.Password; // TODO: 提交登录信息 } else { // 验证失败,重置滑块位置 Canvas.SetLeft(canvasSlider, 0); } } ``` 在代码中,我们使用了 PointerPressed、PointerMoved 和 PointerReleased 事件来实现滑块的拖动,并在 PointerReleased 事件中进行验证。当滑块被拖动到正确的位置时,我们可以提交用户的登录信息给服务器进行验证。否则,重置滑块位置并提示用户验证失败。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值