WPF整数验证

28 浏览
0 Comments

WPF整数验证

我正在使用INotifyDataErrorInfo,并使用这个实现:https://kmatyaszek.github.io/wpf-validation/2019/03/13/wpf-validation-using-inotifydataerrorinfo.html

链接失效时的代码:

public class MainViewModel : BindableBase, INotifyDataErrorInfo
{
    private string _userName;
    private readonly Dictionary> _errorsByPropertyName = new Dictionary>();
    public MainViewModel()
    {
        UserName = null;
    }
    public string UserName
    {
        get => _userName;
        set
        {
            _userName = value;
            ValidateUserName();
            RaisePropertyChanged();
        }
    }
    public bool HasErrors => _errorsByPropertyName.Any();
    public event EventHandler ErrorsChanged;
    public IEnumerable GetErrors(string propertyName)
    {
        return _errorsByPropertyName.ContainsKey(propertyName) ?
            _errorsByPropertyName[propertyName] : null;
    }
    private void OnErrorsChanged(string propertyName)
    {
        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
    }
    private void ValidateUserName()
    {
        ClearErrors(nameof(UserName));
        if (string.IsNullOrWhiteSpace(UserName))
            AddError(nameof(UserName), "用户名不能为空。");
        if (string.Equals(UserName, "Admin", StringComparison.OrdinalIgnoreCase))
            AddError(nameof(UserName), "Admin不是有效的用户名。");
        if (UserName == null || UserName?.Length <= 5)
            AddError(nameof(UserName), "用户名必须至少为6个字符长。");
    }
    private void AddError(string propertyName, string error)
    {
        if (!_errorsByPropertyName.ContainsKey(propertyName))
            _errorsByPropertyName[propertyName] = new List();
        if (!_errorsByPropertyName[propertyName].Contains(error))
        {
            _errorsByPropertyName[propertyName].Add(error);
            OnErrorsChanged(propertyName);
        }
    }
    private void ClearErrors(string propertyName)
    {
        if (_errorsByPropertyName.ContainsKey(propertyName))
        {
            _errorsByPropertyName.Remove(propertyName);
            OnErrorsChanged(propertyName);
        }
    }
}

它工作得很好,但现在我想验证整数值,而不是字符串。基本上,用户不应该输入除int以外的任何内容,否则应用程序将崩溃。但是,我不知道该如何编写ValidateIntegerValue()方法,因为我无法检查int是否是int,因为在后端它总是整数。

0
0 Comments

WPF整数验证

WPF中的整数验证问题是因为int属性只能被设置为int值,而不是由视图模型来验证视图或视图中的控件是否尝试将其设置为其他值,因为这总是会失败。视图模型只是公开属性,设置属性的责任在于视图。

首先要理解的是,这种类型的验证应该在视图或控件中进行。绑定到字符串属性,然后在视图模型中转换值是一个不好的主意。

相反,你可以创建一个自定义的ValidationRule:

public class StringToIntValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        int i;
        if (int.TryParse(value.ToString(), out i))
            return new ValidationResult(true, null);
        return new ValidationResult(false, "Please enter a valid integer value.");
    }
}

然后将其与绑定关联:


    
        
            
                
            
        
    

如果你想阻止用户输入无效的值,你可以处理TextBox的PreviewTextInput事件或创建一个自定义控件。这与视图模型无关。

为什么存在INotifyDataErrorInfo?它更多是根据情况使用两者。

INotifyDataErrorInfo用于在视图模型中实现数据验证。它不能用于验证视图中的控件如何设置源属性。

INotifyDataErrorInfo有一个HasErrors属性,所以如果有错误,可以很容易地阻止任何控件。这里能做类似的事情吗?如果不能,用户仍然可以破坏事物。

除非你以某种方式设置视图模型的某个属性,否则你不能轻易地阻止任何控件。根据你的具体要求,你可能最好是阻止特定字符进入TextBox。

另一个问题是0.5变成了5。嗯,INotifyDataErrorInfo可能不是完美的,但至少它工作了。

问题是什么?你特定的实现问题?从这个问题和你的问题的答案中可以得出的关键是,除非你选择绑定到字符串属性(你不应该这样做),否则你只能在视图中处理这个问题。

是的,这个解决方案似乎相当不完美,但是ValidationRule将0.5变成了5,所以我要么选择丑陋的解决方案,要么选择不起作用的解决方案。它似乎只适用于整数,不适用于小数(我已经为小数实现了)。

验证规则只是验证值并返回一个ValidationResult。它不会将源属性设置为其他值。

可能是UpdateSourceTrigger="PropertyChanged"改变了值。尝试移除它。然后你应该得到与之前相同的行为,关于如何设置属性。

我一开始就没有使用它。默认情况下,它会删除0。我发现你可以调整decimal.Parse,但它在decimal.TryParse上不起作用。

再次强调,验证规则本身不会删除任何内容。当然,decimal.TryParse是有效的。如果你有其他问题,请提出新的问题。

已解决。它仍然会自动删除逗号,但是这个decimal.TryParse(value.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out i)至少接受点。而且显然WPF足够智能,能够根据是否有错误来默认阻止我想要的控件。感谢帮助,这是非字符串的完美实现。

好吧,它并没有阻止它。好吧,我要回到INotifyDataErrorInfo了。ValidationRules没有提供任何有效的方法来阻止所需的控件,我认为它们是无用的,除非我们确定用户不会破坏任何东西,但我们不能假设。

它们不应该被用来阻止。它们应该用于验证。阻止是控件的责任。

0