我在表单上有 2 个字符串数据字段。我的规则是两个数据字段的值不能相同且不能为空。看来检查规则确实有效,因为在值再次更改之前不会再次引发更改的数据。例如:F1 = F2 空字符串 ==> 无效数据。 F1 = 1,F2 =2 ==> 通过。 F1=2; F2 = 2 ==> F1 无效(红色矩形)。 F2= 3 ==> F1 仍然有红色矩形,因为数据没有改变,所以它不会再次计算,虽然屏幕上显示 F1 <> F2 但错误消息仍然是 F1 = F2。如果我将 F1 更改为其他内容并返回到 2,那么就可以了,因为它已被再次评估。当用户尝试保存表单时,我最终检查了 F1 和 F2 数据字段。你会如何处理这种情况?谢谢
using Simplified;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Core2023.SO.ThichCoiPhim
{
public class TwoFieldsVM : ViewModelBase, INotifyDataErrorInfo
{
public string Field1 { get => Get<string>(); set => Set(value); }
public string Field2 { get => Get<string>(); set => Set(value); }
public bool HasErrors => !Errors.All(pair => string.IsNullOrEmpty(pair.Value));
public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;
public IEnumerable GetErrors(string? propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
foreach (var pair in Errors)
{
if (!string.IsNullOrEmpty(pair.Value))
yield return $"{pair.Key}: {pair.Value}";
}
}
else if (Errors.TryGetValue(propertyName, out var errors))
{
if (!string.IsNullOrEmpty(errors))
yield return $"{propertyName}: {errors}";
}
}
private readonly Dictionary<string, string> Errors = new()
{
{ nameof(Field1), Field1EmptyError },
{ nameof(Field2), Field2EmptyError },
};
private const string Field1EmptyError = $"{nameof(Field1)} Empty";
private const string Field2EmptyError = $"{nameof(Field2)} Empty";
private const string Field1EqualsField2Error = $"{nameof(Field1)} Equals {nameof(Field2)}";
protected override void OnPropertyChanged(string propertyName, object? oldValue, object? newValue)
{
base.OnPropertyChanged(propertyName, oldValue, newValue);
if (propertyName is nameof(Field1) or nameof(Field2))
{
bool f1 = string.IsNullOrEmpty(Field1);
bool f2 = string.IsNullOrEmpty(Field2);
string fe1 = Errors[nameof(Field1)];
string fe2 = Errors[nameof(Field2)];
if (f1 || f2)
{
Errors[nameof(Field1)] = f1 ? Field1EmptyError : string.Empty;
Errors[nameof(Field2)] = f2 ? Field2EmptyError : string.Empty;
}
else if (Field1 == Field2)
{
Errors[nameof(Field1)] = Field1EqualsField2Error;
Errors[nameof(Field2)] = string.Empty;
}
else
{
Errors[nameof(Field1)] = string.Empty;
Errors[nameof(Field2)] = string.Empty;
}
if (fe1 != Errors[nameof(Field1)])
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(Field1)));
}
if (fe2 != Errors[nameof(Field2)])
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(Field2)));
}
}
}
}
}
<Window x:Class="Core2023.SO.ThichCoiPhim.TwoFieldsWindow"
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:Core2023.SO.ThichCoiPhim"
mc:Ignorable="d"
Title="TwoFieldsWindow" Height="450" Width="800">
<Window.DataContext>
<local:TwoFieldsVM/>
</Window.DataContext>
<UniformGrid>
<TextBox x:Name="textBox1" Text="{Binding Field1, UpdateSourceTrigger=PropertyChanged}" Margin="10"/>
<TextBox x:Name="textBox2" Text="{Binding Field2, UpdateSourceTrigger=PropertyChanged}" Margin="10"/>
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors), ElementName=textBox1, Mode=OneWay}"
DisplayMemberPath="ErrorContent"/>
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors), ElementName=textBox2, Mode=OneWay}"
DisplayMemberPath="ErrorContent"/>
</UniformGrid>
</Window>