bit*_*onk 6 validation wpf controltemplate
这是前一个问题的后续问题,它并没有真正让我到处: WPF中的确定性和异步字段验证
由于WPF似乎不支持INotifyDataErrorInfo,我需要自己实现类似的东西(如果我错了,请纠正我).我需要这个,因为我希望ViewModel触发何时为某些字段显示特殊的ErrorTemplates(例如,在单击按钮之后或在长时间运行异步验证操作结束之后或当内部状态以某些字段突然显示的方式更改时)失效).
我正在考虑为此编写自定义标记扩展或行为.它监听我INotifyDataErrorInfo的ViewModel实现的版本,并在ErrorsChanged引发事件后从XAML中定义的特殊的已知ErrorTemplate创建一个VisualTree .
一旦我在XAML中定义了该模板,我如何从我的行为/表达中找到它,从中实现一个实际的可视化树,然后在我表单上的右侧字段条目中显示它(可能以某种方式在一个装饰层上)?
您不需要标记扩展名.我最近发现自己希望有同样的行为,所以我创建了一个适合我需求的解决方案.希望这也有助于你.
该IDataErrorInfo接口实际上包含了进行异步信令所需的一切.它缺少的是一个自动触发通知的事件系统.该接口和INotifyPropertyChanged接口之间存在关系.两者的结合实际上允许您间接地发出变化的信号.
首先控制:
<TextBox
Grid.Column="1"
Width="100"
Text="{Binding UpdateSourceTrigger=LostFocus,
Path=Id,
ValidatesOnDataErrors=true}" />
Run Code Online (Sandbox Code Playgroud)
非常直截了当.值UpdateSourceTrigger并不重要,并且NotifyOnValidationError不是必需的,但如果添加它不会伤害任何东西.
接下来是视图模型,这只是一个人为的例子.重要的部分是IDataErrorInfo索引器.
public class WindowViewModel : INotifyPropertyChanged, IDataErrorInfo
{
public event PropertyChangedEventHandler PropertyChanged;
private int _id;
public int Id
{
get{ return _id; }
set
{
_id = value;
this.PropertyChanged( this, new PropertyChangedEventArgs( "Id" ) );
}
}
public string this[ string columnName ]
{
get
{
object result = AsynchValidationCoordinator.GetError( columnName );
if ( result != null )
{
return result.ToString();
}
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
AsynchValidationCoordinator是一个跟踪属性和任何相关错误信息的类.出于说明的目的,使用的密钥只是属性名称,但您可以轻松创建复合键,以区分具有多个视图模型的方案中的潜在属性冲突.
public static class AsynchValidationCoordinator
{
private static readonly ConcurrentDictionary<string, object> ErrorList =
new ConcurrentDictionary<string, object>();
public static void CancelError( string propertyName, object error )
{
object value;
ErrorList.TryRemove( propertyName, out value );
}
public static object GetError( string propertyName )
{
object error = null;
if ( ErrorList.ContainsKey( propertyName ) )
{
ErrorList.TryRemove( propertyName, out error );
}
return error;
}
public static void RegisterError( string propertyName, object error )
{
ErrorList[propertyName] = error;
}
}
Run Code Online (Sandbox Code Playgroud)
跟踪属性名称是必要的,但您可以创建一种完全不同的跟踪方式,包括跟踪视图模型中的名称.这对我来说只是一种简单的方法,可以快速将结构化表单应用到现有项目中.
因此将所有这些绑定在一起,我将以下ICommand属性添加到测试视图模型并将其绑定到Button.(RelayCommand来自Josh Smith的MSDN MVVM文章.)
public ICommand ValidateCommand
{
get
{
return new RelayCommand( Validate );
}
}
private void Validate( object value )
{
Thread thread = new Thread( RaiseChanged );
thread.Start();
}
private void RaiseChanged()
{
Thread.Sleep( 3000 );
AsynchValidationCoordinator.RegisterError( "Id", "Error Message Goes Here" );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Id" ) );
}
Run Code Online (Sandbox Code Playgroud)
通话的来源无关紧要.将所有这些联系在一起的重要一点是,一旦PropertyChanged被调用,IDataErrorInfo索引器就会跟随它.返回已注册的错误信息AsynchValidationCoordinator会触发Validation.ErrorTemplate控件的相关错误消息.