【问题标题】:WPF ValidationRule and DataTrigger to disable Submit buttonWPF ValidationRule 和 DataTrigger 禁用提交按钮
【发布时间】:2020-11-10 17:40:26
【问题描述】:

在下面的 XAML 中,我使用 MultiDataTriggerValidationRule 尝试保留提交按钮 disabled,直到两个文本框输入了有效值(字母数字)。这可以正常工作,因为当值无效时(例如,some@test)按钮会被禁用,而当您使该值有效时(例如,sometest),它会启用按钮。

问题:但是当您启动应用程序时,它会将按钮显示为已启用 - 这违背了整个目的,因为即使您尚未开始输入文本框值也可以提交按钮。

问题:我可能在这里遗漏了什么,我们该如何解决?

备注:如果您查看(并且我测试了)上面第一个链接中的 MultiDataTrigger 示例,您会注意到(如两个图像所示)初始值(如预期的那样)显示为Unverified,颜色为red,当您选中两个复选框时,文本值将变为Verified,颜色为绿色。所以,似乎我在上面的 XAML 中显然遗漏了一些东西。请注意,我已将按钮的初始状态设置为<Setter Property="IsEnabled" Value="False"/>

<Window x:Class="WPF_DataValidation.MainWindow"
        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:local="clr-namespace:WPF_DataValidation"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        
        <local:MyDataSource x:Key="myds"/>

        <ControlTemplate x:Key="ValidationTemplate">
            <DockPanel>
                <TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red" DockPanel.Dock="Bottom" Grid.Row="1"/>
                <AdornedElementPlaceholder/>
            </DockPanel>
        </ControlTemplate>
        <Style TargetType="Label">
            <Setter Property="Margin" Value="5" />
            <Setter Property="VerticalAlignment" Value="Center" />
        </Style>
        <Style x:Key="DefaultTextBoxStyle" TargetType="TextBox">
            <Setter Property="Margin" Value="5" />
            <Setter Property="VerticalAlignment" Value="Center" />
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="Labels" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Label Name="lblFirstName">First Name:</Label>
        <TextBox Name="txtFirstName" Grid.Column="1" Style="{StaticResource DefaultTextBoxStyle}" Validation.ErrorTemplate="{StaticResource ValidationTemplate}">
            <TextBox.Text>
                <Binding Path="FirstName" Source="{StaticResource myds}" UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <local:AlphanumericOnlyValidationRule/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <Label Name="lblLastName" Grid.Row="1">Last Name:</Label>
        <TextBox Name="txtLastName" Grid.Row="1" Grid.Column="1" Style="{StaticResource DefaultTextBoxStyle}" Validation.ErrorTemplate="{StaticResource ValidationTemplate}">
            <TextBox.Text>
                <Binding Path="LastName" Source="{StaticResource myds}" UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <local:AlphanumericOnlyValidationRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <Button x:Name="btnTest" Content="Test" Grid.Row="2" HorizontalAlignment="Right">
            <Button.Style>
                <Style TargetType="Button">
                    <Setter Property="IsEnabled" Value="False"/>
                    <Style.Triggers>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding Path=(Validation.HasError), ElementName=txtFirstName}" Value="False"/>
                                <Condition Binding="{Binding Path=(Validation.HasError), ElementName=txtLastName}" Value="False"/>
                            </MultiDataTrigger.Conditions>
                            <Setter Property="IsEnabled" Value="True"/>
                        </MultiDataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>
    </Grid>
</Window>

MyDataSource.cs

public class MyDataSource
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

AlphanumericOnlyValidationRule.cs

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

namespace WPF_DataValidation
{
    public class AlphanumericOnlyValidationRule: ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            string sVal = value as string;

            if (string.IsNullOrEmpty(sVal))
            {
                return new ValidationResult(false, "Please enter some text");
            }

            if (!sVal.All(char.IsLetterOrDigit))
            {
                //Note: this will also return false if text has a blank space
                return new ValidationResult(false, "This field must contain alphanumeric characcters only");
            }

            return new ValidationResult(true, null);
        }
    }
}

观察

问题似乎是,当应用程序第一次加载时,它可能首先会禁用提交按钮。但是 XAML 的 MultiDataTrigger.Conditions 块中的值 Validation.HasError 假定没有验证错误(因为应用程序刚刚加载并且用户尚未采取任何操作),因此它再次启用提交按钮。这只是我基于以下 XAML 的观察,我通过修改 MultiDataTrigger example 使用如下所示。在这里,我只是将TextBlock 更改为Button 以及相应的值,并注意到最初按钮被禁用(因为默认情况下复选框未选中),当您选中两个复选框时,按钮将启用(如预期的那样)。因此,我们可能需要了解如何(在上述 XAML 中)在应用初始加载时禁用该按钮。

网上修改的 XAML MiltiDataTrigger Example:

<Button.Style>
    <Style TargetType="Button">
         <Setter Property="IsEnabled" Value="False"/>
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=(Validation.HasError), ElementName=txtFirstName}" Value="False"/>
                        <Condition Binding="{Binding Path=(Validation.HasError), ElementName=txtLastName}" Value="False"/>
                    </MultiDataTrigger.Conditions>
                  <Setter Property="IsEnabled" Value="True"/>
              </MultiDataTrigger>
            </Style.Triggers>
         </Style>
</Button.Style>

【问题讨论】:

    标签: wpf validation xaml


    【解决方案1】:

    这是自验证发生以来的预期行为

    (...)当目标的值被传输到绑定源时 属性。

    source

    在您的情况下,甚至在更新控件的值之前强制验证,您可以将ValidatesOnTargetUpdated="True" 属性添加到ValidationRule,它会在更新 Binding 的目标时触发验证。

    <TextBox
        Name="txtLastName"
        Grid.Row="1"
        Grid.Column="1"
        Style="{StaticResource DefaultTextBoxStyle}"
        Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
        >
        <TextBox.Text>
            <Binding
                Path="LastName"
                Source="{StaticResource myds}"
                UpdateSourceTrigger="PropertyChanged"
                >
                <Binding.ValidationRules>
                    <local:AlphanumericOnlyValidationRule ValidatesOnTargetUpdated="True" />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
    

    ValidationRule.ValidatesOnTargetUpdated - MS DOC

    【讨论】:

    • 你的建议很有效。欢迎来到StackOverflow - 并特别感谢NICELY 用所有相关参考资料解释问题的原因,因为这对我来说都很重要(希望对您回复的其他读者也很重要)。
    猜你喜欢
    • 2012-10-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2011-03-12
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 2010-12-30
    相关资源
    最近更新 更多