#wpf #validation #xaml
#wpf #проверка #xaml
Вопрос:
В следующем XAML я использую MultiDataTrigger и ValidationRule, пытаясь удерживать кнопку отправки 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);
}
}
}
НАБЛЮДЕНИЕ
Проблема, похоже, в том, что при загрузке приложения в первый раз оно, вероятно, сначала отключает кнопку отправки. Но значение Validation.HasError
в MultiDataTrigger.Conditions
блоке XAML предполагает, что ошибки проверки нет (поскольку приложение только что загружено, а пользователь еще не предпринял никаких действий), и, следовательно, оно снова включает кнопку отправки. Это всего лишь мое наблюдение, основанное на следующем XAML, который я использовал, изменив пример MultiDataTrigger, как показано ниже. Здесь я просто изменил значение TextBlock
на Button
вместе с соответствующими значениями и заметил, что изначально кнопка отключена (поскольку флажки по умолчанию не установлены), и когда вы устанавливаете оба флажка, кнопка включается (как и ожидалось). Итак, нам, вероятно, нужно посмотреть, как (в приведенном выше XAML) мы можем отключить кнопку при начальной загрузке приложения.
MiltiDataTrigger Пример модифицированного XAML из онлайн:
<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>
Ответ №1:
Это ожидаемое поведение, поскольку происходит проверка
(…) когда значение целевого объекта передается свойству источника привязки.
В вашем случае, чтобы принудительно выполнить проверку, прежде чем даже обновлять значение элементов управления, вы можете добавить ValidatesOnTargetUpdated="True"
свойство ValidationRule
, и оно запустит проверку при обновлении целевого объекта привязки.
<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>
Комментарии:
1. Ваше предложение сработало как шарм. Добро пожаловать в
StackOverflow
— и благодарю вас заNICELY
объяснение причины проблемы со всеми соответствующими ссылками, поскольку это было важно для меня (и, надеюсь, для некоторых других читателей вашего ответа).