wpf - 处理无法转换 WPF 中双属性的值
问题描述
情况
我有文本框,它绑定到类型为double
.
当用户尝试在框中输入字母时,会显示:
而且,这显示在绑定失败中。
我目前有这个验证来检查null
价值并且工作正常。
public Dictionary<string, string> Errors { get; } = new Dictionary<string, string>();
public string this[string propertyName]
{
get
{
CollectionErrors();
return Errors.ContainsKey(propertyName) ? Errors[propertyName] : string.Empty;
}
}
private void CollectionErrors()
{
Errors.Clear();
if(NumberProp == null)
{
Errors.Add(nameof(NumberProp), "This value cannot be empty");
}
}
public string Error => string.Empty;
public bool HasErrors => !Errors.Any(); // To determine if there are any errors
输出
问题
我该如何处理could not be converted
?
到目前为止我试过这个:
if(NumberProp.GetType() == typeof(string))
{
Errors.Add(nameof(NumberProp), "NumberProp cannot contain any letters!");
}
但是得到这个错误:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
为什么我需要这个
我有一个按钮,在验证失败时禁用或在一切正常时启用。
SendDataCommand = new RelayCommand((x) => { SendData(); }, (y) => HasErrors);
显示错误时启用该按钮Value '' could not be converted.
。
编辑 1
XAML
<TextBox Text="{Binding NumberProp, UpdateSourceTrigger=LostFocus, ValidatesOnDataErrors=True, TargetNullValue=''}" />
财产
private double? _numberProp;
public double? NumberProp
{
get { return _numberProp; }
set
{
_numberProp = value;
OnPropertyChanged(nameof(NumberProp));
}
}
解决方案
private void CollectionErrors()
{
Errors.Clear();
if (string.IsNullOrWhiteSpace(NumberProp))
{
Errors.Add(nameof(NumberProp), "This value cannot be empty");
}
else if (decimal.TryParse(NumberProp, out _))
{
Errors.Add(nameof(NumberProp), "NumberProp is not a decimal number!");
}
}
最好不要完全清除所有错误,而只清除选中属性的错误:
public Dictionary<string, string> Errors { get; } = new Dictionary<string, string>();
public string this[string propertyName]
{
get
{
CollectionErrors(propertyName);
return Errors.ContainsKey(propertyName) ? Errors[propertyName] : string.Empty;
}
}
private void CollectionErrors(string propertyName)
{
Errors.Remove(propertyName);
if (propertyName == nameof(NumberProp))
{
if (string.IsNullOrWhiteSpace(NumberProp))
{
Errors.Add(nameof(NumberProp), "This value cannot be empty");
}
else if (decimal.TryParse(NumberProp, out _))
{
Errors.Add(nameof(NumberProp), "NumberProp is not a decimal number!");
}
}
}
public string Error => string.Join(Environment.NewLine, Errors.Select(pair => $"[{pair.Key}]=\"{pair.Value}\""));
按照约定(合同)INotifyPropertyChanged 接口,PropertyChanged 事件仅应在属性更改时引发。
因此,正确的实现应该是这样的:
private double _number;
public double Number
{
get { return _number; }
private set
{
if (Equals(_number, value))
return;
_number = value;
OnPropertyChanged(nameof(Number));
}
}
private string _numberProp;
public string NumberProp
{
get { return _numberProp; }
set
{
if (Equals(_numberProp, value))
return;
_numberProp = value;
OnPropertyChanged(nameof(NumberProp));
if (double.TryParse(value, out double number))
Number = number;
}
}
具有两个绑定属性的类实现的完整示例。
NumberString - 用于绑定到 TextBox。
Number - 包含转换为 double 的 NumberString 属性的值。
对这两个属性都实施了错误检查。
还要注意 [CallerMemberName] 属性。
它允许您不在方法中指定属性名称。
public class Data : INotifyPropertyChanged, IDataErrorInfo
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private double _number;
public double Number
{
get { return _number; }
private set
{
if (Equals(_number, value))
return;
_number = value;
CollectionErrors();
OnPropertyChanged();
}
}
private string _numberProp;
public string NumberProp
{
get { return _numberProp; }
set
{
if (Equals(_numberProp, value))
return;
_numberProp = value;
CollectionErrors();
OnPropertyChanged();
if (double.TryParse(value, out double number))
Number = number;
}
}
public Dictionary<string, string> Errors { get; } = new Dictionary<string, string>();
public string this[string propertyName] => Errors[propertyName];
private void CollectionErrors([CallerMemberName] string propertyName = null)
{
if (propertyName == null)
return;
Errors.Remove(propertyName);
if (propertyName == nameof(NumberProp))
{
if (string.IsNullOrWhiteSpace(NumberProp))
{
Errors[nameof(NumberProp)] = "This value cannot be empty";
}
else if (decimal.TryParse(NumberProp, out _))
{
Errors[nameof(NumberProp)] = "NumberProp is not a decimal number!";
}
}
else if (propertyName == nameof(Number))
{
if (Number < 0 || Number > 1000)
Errors[nameof(Number)] = "The number must be in the range 0 ... 1000!";
}
}
public string Error => string.Join(Environment.NewLine, Errors.Select(pair => $"[{pair.Key}]=\"{pair.Value}\""));
}
推荐阅读
- c++ - “对于可能的堆栈重载数组,索引“8”超出了有效范围“0 到 1””。我将如何解决这个问题?
- javascript - useStates 的 setState 在函数 handleNew 中未设置值,我必须
- flutter - 如何在不影响其他小部件的情况下将文本置于底部?
- android - 跟踪通过 Google Analytics 上的应用打开浏览器的用户
- javascript - js onkeyup 在移动设备上不起作用
- python - 学习曲线和验证曲线 sklearn
- android - 在哪里声明应用程序的所有活动中使用的变量和函数(Kotlin)
- r - 选择冲击大小并登录脉冲响应函数
- python-3.x - 有什么方法可以在 Python 中使用 SQLite 将变量用作添加列的名称?
- r - 我无法在 r 中的 for{} 中使用 tiff() 保存文件