On ValidatesOnExceptions UI 未更新

On ValidatesOnExceptions UI is not updating

给出的是一个 Wpf .Net5.0 应用程序 带有重置按钮和文本框

当路径有效时,我可以重置为默认值。 UI 更新 当用户输入无效字符时,边框变为红色且重置按钮未更新 UI.

我尝试通过 Snoop 进行调试,看起来 VM 正在重置。但不是 UI。 怎么了?

工作演示:https://github.com/LwServices/WpfValidationDemo/tree/master/ValidationWpf

由于缺少 CanExecute 方法而被禁用,请使用下面的代码

    internal class MainWindowViewModel : NotifyPropertyChanged {

    private DelegateCommand _resetCmd;
    public ICommand ResetCommand => _resetCmd ?? new DelegateCommand(Reset, canRest);

    

    private string _filePath;

    public string FilePath
    {
        get => _filePath;
        set
        {
            var r = new Regex(@"[\w\s\.:\-!~]");
            if (r.Matches(value).Count == value.Length)
            {
                SetProperty(ref _filePath, value);
                return;
            }

            throw new ArgumentException("Not an valid windows path");
        }
    }

    public MainWindowViewModel()
    {
    }

    private void Reset(object obj)
    {
        FilePath = @"C:\Temp";
    }
    private bool canRest() {
        return true;
    }
}

简单的解决方案

设置值后直接通知UI即可解决

private void Reset()
{
    FilePath = @"C:\Temp";
    OnPropertyChanged(nameof(FilePath));
}

问题原因

Filepath 与您的正则表达式不匹配时,您只需引发异常而不修改 _filePath 的值,它将始终是有效路径

public string FilePath
{
    get => _filePath;
    set
    {
        var r = new Regex(@"[\w\s\.:\-!~]");
        if (r.Matches(value).Count == value.Length)
        {
            SetProperty(ref _filePath, value); //<<<<<< this will never call if the value passed from the ui doesnot match Regex
            return;
        }

        throw new ArgumentException("Not an valid windows path");
    }
}

当您调用 reset() 时,您尝试将 Filepath 设置为 c:/temp 并且如果 _filePath 的最后一个值相等到c:/temp问题会从下面

出现
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
   if (EqualityComparer<T>.Default.Equals(field, value)) return false;  /// your code will return 
   field = value;
   OnPropertyChanged(propertyName); // before notify the UI
   return true;
}

因此,正如开头所建议的,简单的解决方案是直接通知您的 UI SetProperty 方法中删除检查行

if (EqualityComparer<T>.Default.Equals(field, value)) return false;