您不需要标记扩展。最近我也希望有相同的行为,所以我创建了一个适合我的需求的解决方案。希望这也能帮到您。
实际上,
IDataErrorInfo
接口包含了我们进行异步信号传递所需的一切。它缺少的是一个自动触发通知的事件系统。该接口与
INotifyPropertyChanged
接口之间存在关系。两者的组合实际上允许您间接地发出更改信号。
首先是控件:
<TextBox
Grid.Column="1"
Width="100"
Text="{Binding UpdateSourceTrigger=LostFocus,
Path=Id,
ValidatesOnDataErrors=true}" />
很简单。
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;
}
}
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;
}
}
跟踪属性名称是必要的,但您可以创建完全不同的跟踪方式,包括跟踪视图模型中的名称。这只是我快速将结构化表单应用于现有项目的简单方法。
因此,将所有这些绑定在一起,我向测试视图模型添加了以下属性,并将其绑定到按钮上。(来自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" ) );
}
调用的源始无关紧要。将所有内容联系在一起的重要一点是,一旦调用
PropertyChanged
,
IDataErrorInfo
索引器就会跟随其轨迹。返回在
AsynchValidationCoordinator
中注册的错误信息将触发控件的
Validation.ErrorTemplate
,显示相关的错误消息。
BindingGroup
来显式触发验证。 - bitbonk