C# HasError为false时未清除验证错误装饰
导言 我创建了一个C# HasError为false时未清除验证错误装饰,c#,wpf,validation,xaml,adorner,C#,Wpf,Validation,Xaml,Adorner,导言 我创建了一个DecimalTextBox用户控件,该控件附加了ValidationRules以防止为空,具有最小和最大范围,并具有事件处理程序以防止非十进制值。我用过 ValidatesOnTargetUpdated="True" 在绑定上,因为我希望立即激活验证(之前我遇到过一个问题,最小值和最大值都在更改,但验证没有重新评估) 我所做的空验证依赖于“AllowNull”依赖属性的值:如果控件指定true,那么即使该值为空,该控件也是有效的。如果为false,则不允许为null。此属性
DecimalTextBox
用户控件,该控件附加了ValidationRule
s以防止为空,具有最小和最大范围,并具有事件处理程序以防止非十进制值。我用过
ValidatesOnTargetUpdated="True"
在绑定上,因为我希望立即激活验证(之前我遇到过一个问题,最小值和最大值都在更改,但验证没有重新评估)
我所做的空验证依赖于“AllowNull”依赖属性的值:如果控件指定true,那么即使该值为空,该控件也是有效的。如果为false,则不允许为null。此属性的默认值为False
问题 在某个用户控件中使用AllowNull时,我将其设置为
true
。不幸的是,由于validateOnTargetUpdated
设置为true
,因此在xaml将AllowFull设置为true
之前,控件将被验证,而它仍然处于默认的false
设置中
这会在加载之前导致错误,因为与文本框
文本的绑定也尚未解析,因此在加载之前不允许null,并且文本的值为null
这一切都很好,因为加载后,将使用新的AllowFull值(为true)重新评估验证,并消除错误
然而红色的装饰仍然存在。不完全确定如何摆脱它
代码 textbox用户控件的xaml:
<UserControl x:Class="WPFTest.DecimalTextBox"
x:Name="DecimalBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:v="clr-namespace:ValidationRules"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="100" Initialized="DecimalBox_Initialized" >
<TextBox x:Name="textbox">
<TextBox.Text>
<Binding ElementName="DecimalBox" TargetNullValue="" Path="Text" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay" ValidatesOnDataErrors="True" ValidatesOnExceptions="True" NotifyOnValidationError="True">
<Binding.ValidationRules>
<v:DecimalRangeRule ValidatesOnTargetUpdated="True">
<v:DecimalRangeRule.MinMaxRange>
<v:MinMaxValidationBindings x:Name="minMaxValidationBindings"/>
</v:DecimalRangeRule.MinMaxRange>
</v:DecimalRangeRule>
<v:NotEmptyRule ValidatesOnTargetUpdated="True">
<v:NotEmptyRule.AllowNull>
<v:AllowNullValidationBinding x:Name="allowNullValidationBindings"></v:AllowNullValidationBinding>
</v:NotEmptyRule.AllowNull>
</v:NotEmptyRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</UserControl>
以及验证规则(#注意:它们位于ValidationRules命名空间中):
public类NotEmptyRule:ValidationRule
{
公共NotEmptyRule()
{
}
私有AllowNullValidationBinding_allowNullBinding;
公共AllowNullValidationBinding AllowNull
{
获取{return\u allowNullBinding;}
设置{u allowNullBinding=value;}
}
公共覆盖验证结果验证(对象值,CultureInfo CultureInfo)
{
如果(!\u allowNullBinding.AllowNull)
if(string.IsNullOrEmpty((string)值))
返回新的ValidationResult(false,
“值不能为null或空。”);
其他的
返回新的ValidationResult(true,null);
其他的
返回新的ValidationResult(true,null);
}
}
公共类小数范围规则:ValidationRule
{
私有MinMaxValidationBindings_bindableMinMax;
公共MinMaxValidationBindings MinMaxRange
{
获取{return\u bindableMinMax;}
设置
{
_bindableMinMax=值;
}
}
公共小数范围规则()
{
}
公共覆盖验证结果验证(对象值,CultureInfo CultureInfo)
{
十进制数=0;
if(十进制三分位((字符串)值,输出编号))
如果(_bindableMinMax.Min!=_bindableMinMax.Max | | _bindableMinMax.Min!=0)
{
如果((数字<_bindableMinMax.Min)| |(数字>_bindableMinMax.Max))
{
返回新的ValidationResult(false,
请在以下范围内输入小数:“+\u bindableMinMax.Min+”-“+\u bindableMinMax.Max+”;
}
其他的
{
返回新的ValidationResult(true,null);
}
}
其他的
返回新的ValidationResult(true,null);
其他的
返回新的ValidationResult(true,null);
}
}
公共类AllowNullValidationBinding:FrameworkElement
{
公共静态只读DependencyProperty allowNullProperty=DependencyProperty.Register(
“AllowNull”、typeof(bool)、typeof(AllowNullValidationBinding)、新UIPropertyMetadata(false));
公共布尔AllowNull
{
获取{return(bool)GetValue(allowNullProperty);}
set{SetValue(allowNullProperty,value);}
}
公共AllowNullValidationBinding()
{}
}
公共类MinMaxValidationBindings:FrameworkElement
{
公共静态只读DependencyProperty minProperty=DependencyProperty.Register(
“Min”、typeof(十进制)、typeof(MinMaxValidationBindings)、新UIPropertyMetadata(0.0m));
公共静态只读DependencyProperty maxProperty=DependencyProperty.Register(
“Max”、typeof(十进制)、typeof(MinMaxValidationBindings)、新UIPropertyMetadata(0.0m));
公共十进制最小值
{
获取{return(decimal)GetValue(minProperty);}
set{SetValue(minProperty,value);}
}
公共十进制最大值
{
get{return(十进制)GetValue(maxProperty);}
set{SetValue(maxProperty,value);}
}
公共MinMaxValidationBindings(){}
}
使用FrameworkElement绑定可以使我的ValidationRules具有要绑定的依赖项属性。这允许我在控件之外指定最小值和最大值
摘要 加载后,我使用
验证.GetHasError(DecimalBox)
(对于控件本身以及控件内部的文本框
)检查了HasError
,并生成false
我知道,如果我删除validateOnTargetUpdated=“True”
将不会显示红色,但我需要它。那么,为什么验证被重新评估,但红色边框装饰没有消失呢
我不太了解Validation类或它的静态方法,但是其中是否有一些东西可以去除装饰。ClearInvalid方法不会有帮助,因为我没有提供它的错误
有什么想法吗
u_
编辑 我做了更多的调查,发现了以下几点:
public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(textboxcontrol), new PropertyMetadata());
public static DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(decimal), typeof(DecimalTextBox), new PropertyMetadata(0M));
public static DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(decimal), typeof(DecimalTextBox), new PropertyMetadata(0M));
public static DependencyProperty AllowNullProperty = DependencyProperty.Register("AllowNull", typeof(bool), typeof(DecimalTextBox), new UIPropertyMetadata(false));
public bool AllowNull
{
get { return (bool)GetValue(AllowNullProperty); }
set { SetValue(AllowNullProperty, value); }
}
public decimal Minimum
{
get { return (decimal)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public decimal Maximum
{
get { return (decimal)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
private void DecimalBox_Initialized(object sender, EventArgs e)
{
Binding minBinding = new Binding("Minimum");
minBinding.Source = this;
Binding maxBinding = new Binding("Maximum");
maxBinding.Source = this;
Binding allownullBinding = new Binding("AllowNull");
allownullBinding.Source = this;
minMaxValidationBindings.SetBinding(ValidationRules.MinMaxValidationBindings.minProperty, minBinding);
BindingOperations.SetBinding(minMaxValidationBindings, ValidationRules.MinMaxValidationBindings.maxProperty, maxBinding);
BindingOperations.SetBinding(allowNullValidationBindings, ValidationRules.AllowNullValidationBinding.allowNullProperty, allownullBinding);
}
public class NotEmptyRule : ValidationRule
{
public NotEmptyRule()
{
}
private AllowNullValidationBinding _allowNullBinding;
public AllowNullValidationBinding AllowNull
{
get { return _allowNullBinding; }
set { _allowNullBinding = value; }
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (!_allowNullBinding.AllowNull)
if (string.IsNullOrEmpty((string)value))
return new ValidationResult(false,
"Value cannot be null or empty.");
else
return new ValidationResult(true, null);
else
return new ValidationResult(true, null);
}
}
public class DecimalRangeRule : ValidationRule
{
private MinMaxValidationBindings _bindableMinMax;
public MinMaxValidationBindings MinMaxRange
{
get { return _bindableMinMax; }
set
{
_bindableMinMax = value;
}
}
public DecimalRangeRule()
{
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
decimal number = 0;
if(decimal.TryParse((string)value,out number))
if (_bindableMinMax.Min != _bindableMinMax.Max || _bindableMinMax.Min != 0)
{
if ((number < _bindableMinMax.Min) || (number > _bindableMinMax.Max))
{
return new ValidationResult(false,
"Please enter an decimal in the range: " + _bindableMinMax.Min + " - " + _bindableMinMax.Max + ".");
}
else
{
return new ValidationResult(true, null);
}
}
else
return new ValidationResult(true, null);
else
return new ValidationResult(true, null);
}
}
public class AllowNullValidationBinding:FrameworkElement
{
public static readonly DependencyProperty allowNullProperty = DependencyProperty.Register(
"AllowNull", typeof(bool), typeof(AllowNullValidationBinding), new UIPropertyMetadata(false));
public bool AllowNull
{
get{return (bool)GetValue(allowNullProperty);}
set{SetValue(allowNullProperty,value);}
}
public AllowNullValidationBinding()
{}
}
public class MinMaxValidationBindings : FrameworkElement
{
public static readonly DependencyProperty minProperty = DependencyProperty.Register(
"Min", typeof(decimal), typeof(MinMaxValidationBindings), new UIPropertyMetadata(0.0m));
public static readonly DependencyProperty maxProperty = DependencyProperty.Register(
"Max", typeof(decimal), typeof(MinMaxValidationBindings), new UIPropertyMetadata(0.0m));
public decimal Min
{
get { return (decimal)GetValue(minProperty); }
set { SetValue(minProperty, value); }
}
public decimal Max
{
get { return (decimal)GetValue(maxProperty); }
set { SetValue(maxProperty, value); }
}
public MinMaxValidationBindings() { }
}
Validation.ClearInvalid(SystemCode.GetBindingExpression(TextBox.TextProperty));
var dp = SystemCode.GetBindingExpression(TextBox.TextProperty);
dp.UpdateSource();
var depPropGetter = typeof (Validation).GetField("ValidationAdornerProperty", BindingFlags.Static | BindingFlags.NonPublic);
var validationAdornerProperty = (DependencyProperty)depPropGetter.GetValue(null);
var adorner = (Adorner)DateActionDone.GetValue(validationAdornerProperty);
if (adorner != null && Validation.GetHasError(MyControl))
{
var adorners = AdornerLayer.GetAdornerLayer(MyControl).GetAdorners(MyControl);
if (adorners.Contains(adorner))
AdornerLayer.GetAdornerLayer(MyControl).Remove(adorner);
}
string IDataErrorInfo.this[string columnName]
{
get
{
if (_refreshing) return "Refreshing";
return ValidationEngine.For(this.GetType()).GetError(this, columnName);
}
}
bool _refreshing = false;
public void RefreshValidation()
{
_refreshing = true;
this.NotifyOfPropertyChange(string.Empty);
_refreshing = false;
this.NotifyOfPropertyChange(string.Empty);
}
Control.UpdateLayout()