在文本框中插入相同的值 2 次,并检查这些值是否相同 WPF

Insert same value in textbox 2 times and checking the values are the same WPF

提问人:Pomodoro 提问时间:4/4/2023 更新时间:4/5/2023 访问量:34

问:

我正在尝试在 WPF 中实现文本框的功能,以便需要插入一个值 2 次才能被接受为值,否则我需要显示一个错误,例如验证错误等。 我需要在文本框中插入一个值(es:'asd'),然后按 Tab 键文本消失,焦点保留在 texbox 中,然后我需要再次输入相同的文本才能被接受。

现在,我正在尝试通过处理文本框的 PreviewKeyInput 中代码隐藏中的值来做到这一点,但我正试图找到一个更优雅的解决方案。

C# WPF 验证 MVVM 文本框

评论

1赞 JonasH 4/4/2023
我认为这是糟糕的用户设计,因为会有一个用户不可见的隐藏状态。做每个人都做的事情应该要好得多,并且有两个需要匹配的文本字段。或者,用户可能会有一个确认对话框来确认值。
0赞 Pomodoro 4/6/2023
我可以同意你的看法,但这是我的规格:D
0赞 JonasH 4/6/2023
我认为,开发人员有责任抵制糟糕的规范。在规范阶段修复 bug 比在发布后修复要便宜得多,我绝对会将其归类为可用性 bug。如果需要,请进行最简单的实现并将其展示给利益相关者,最好使用非常糟糕的键盘,或者在可能出错的移动设备上。

答:

0赞 Frenchy 4/5/2023 #1

你可以研究这个样本来帮助你。我正在使用 Caliburn.Micro 来实现 MVVM

如果您对 caliburn 不满意,我解释一下:

  1. 创建一个名为 Test 的 wpf .Net 项目,禁止显示创建的文件。MainWindow

  2. 创建一个名为 和 视图模型(类)的窗口(它存在于 Caliburn 中具有名称的逻辑)MainViewMainViewModel

  3. 添加一个名为Bootstrapper.cs

App.xaml 替换为:

<Application x:Class="Test.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Test">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <local:Bootstrapper x:Key="Bootstrapper" />
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

修改文件 Bootstrapper.cs

using Caliburn.Micro;
using System.Windows;

namespace Test
{
    public class Bootstrapper : BootstrapperBase
    {
        public Bootstrapper()
        {
            Initialize();
        }

        protected override async void OnStartup(object sender, StartupEventArgs e)
        {
            await DisplayRootViewForAsync<MainViewModel>();
        }
    }
}

修改 MainView.xaml

<Window x:Class="Test.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:cal="http://www.caliburnproject.org"
        mc:Ignorable="d" 
        Title="MainView" Height="450" Width="800">
    <Grid>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <TextBox x:Name="Login" Width="200" Height="60" Margin="10,10,30,10" Background="AliceBlue" Focusable="True"
                     cal:Message.Attach="[Event LostFocus] = [Action Login_LostFocus($source, $eventargs)];
                                         [Event GotFocus] = [Action Login_GotFocus($source, $eventargs)]"
                     FontSize="12" VerticalContentAlignment="Center" FontWeight="Medium"/>
            <Label Name="Validation" Height="60" Width="400" VerticalContentAlignment="Center"/>
            <Button x:Name="Quit" Content="Quit" Height="60" Width="70" Focusable="True"/>
        </StackPanel>

    </Grid>
</Window>

修改 MainViewModel

using Caliburn.Micro;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Test
{
    public class MainViewModel : Screen
    {
        public string FirstLogin { get; set; }
        private string login;
        public string Login
        {
            get { return login; }
            set
            {
                if (login != value)
                {
                    login = value;
                    NotifyOfPropertyChange(() => Login);
                }
            }
        }

        private string message;
        public string Message
        {
            get { return message; }
            set
            {
                if (message != value)
                {
                    message = value;
                    NotifyOfPropertyChange(() => Message); 
                }
            }
        }

        private string validation;
        public string Validation
        {
            get { return validation; }
            set
            {
                if (validation != value)
                {
                    validation = value;
                    NotifyOfPropertyChange(() => Validation);
                }
            }
        }

        public async void Login_LostFocus(TextBox sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(FirstLogin))
            {
                FirstLogin = Login;
                Login = "";
                //needed before to set focus on TextBox again
                await Task.Delay(100);
                sender.Focus();
            }
            else
            {
                if (FirstLogin.Equals(Login))
                    Validation = "Its Ok!!";
                else
                    Validation = "Its not Ok!!";
            }
        }
        public void Login_GotFocus(TextBox sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(FirstLogin) && !string.IsNullOrEmpty(Login))
            {
                FirstLogin = "";
                Login = "";
            }
            if (string.IsNullOrEmpty(FirstLogin))
                Validation = "First Try";
            else
                Validation = "Second Try";
        }

        public MainViewModel()
        {
            FirstLogin = "";
            Login = "";
            Validation = "";
        }
    }
}

我没有设置按钮退出的操作,它的存在只是为了在TextBox上按Tab键时获得焦点

仅供参考,Caliburn 使用视图文件中的 Control 名称来链接 viewModel 中具有相同名称的属性。

评论

0赞 Pomodoro 4/6/2023
Thansk,我现在没有使用 Caliburn.Micro,但我设法找到了一个像您的解决方案一样,通过在 keydown 事件中处理视图代码隐藏中文本框的值(不是真正符合 mvvm 但是......由于 Textbox.Text 绑定到自定义类属性 (es MyClass.Text),我在类中添加了第二个属性 (TextCheck),首先在键中我检查 TextCheck 是否为空,如果是这样,我分配 TextCheck = Textbox.Text,然后像您一样恢复文本框中的焦点。谢谢。
0赞 Frenchy 4/6/2023
很乐意为您提供帮助,不要忘记验证/点赞答案以结束问题