TextBox上的验证:红色边框并不总是出现在无效结果上

时间:2011-09-29 17:27:20

标签: wpf validation textbox

我有一个绑定到需要值的属性的文本框,即:

 [Required(ErrorMessage = "required value")]
 public string SomeText
 {
     //get set...
 }

在我的XAML中,我的文本框有以下设置:

 UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true, ValidatesOnExceptions=true

正如预期的那样,当文本框中没有值时会出现红色边框,但是当我选择其他选项卡然后返回到包含无效结果的页面时,将不再显示红色边框。如果我输入有效结果然后将其删除,它才会重新出现。

我该如何调试?如何找出导致红色边框出现的事件?

2 个答案:

答案 0 :(得分:8)

在WPF中,当选项卡上的项目从可视树中卸载时,它们被标记为无效的事实将丢失。基本上,当发生验证错误时,UI会响应验证堆栈中的事件并将项目标记为无效。当项目回到可视树中时,不会重新评估此标记,除非重新评估绑定(如果用户单击选项卡项,通常不会这样做。)

在某处定义一个这样的函数(我把它放在一个静态的ValidationHelper类中以及其他一些东西):

public static void ReMarkInvalid( DependencyObject obj )
{
    if( Validation.GetHasError( obj ) ) {
        List<ValidationError> errors = new List<ValidationError>( Validation.GetErrors( obj ) );
        foreach( ValidationError error in errors ) {
            Validation.ClearInvalid((BindingExpressionBase)error.BindingInError);
            Validation.MarkInvalid((BindingExpressionBase)error.BindingInError, error);
        }
    }

    for( int i = 0; i < VisualTreeHelper.GetChildrenCount( obj ); i++ ) {
        ReMarkInvalid( VisualTreeHelper.GetChild( obj, i ) );
    }
}

我认为您可以在TabControl的Selected事件中调用此函数,它应该具有所需的效果。 E.g:

private void TabControl_Selected(...) 
{
    ReMarkInvalid( tabControl );
}

如果这不起作用,您可能需要在较低的Dispatcher优先级下执行此操作,以确保可视树首先完成加载。这看起来像替换ReMarkInvalid ...与:

Dispatcher.BeginInvoke( new Action( delegate()
{
    ReMarkInvalid( tabControl );
} ), DispatcherPriority.Render );

答案 1 :(得分:1)

您只需将标签内容放在 AdornerDecorator 标记内即可:

<TabControl>
    <TabItem>

        <AdornerDecorator>

            <ContentControl Content="{Binding TabItemViewModel}" />
            <Grid>
                <!-- Other Stuff -->
            </Grid>

        </AdornerDecorator>

    </TabItem>
</TabControl>

更新

AdornerDecorator不会对不可见的控件(在未选中的标签中)渲染边框。一旦边框已经渲染,它就会保留标签之间的边框。

但是,Dana Cartwright上面的代码工作得很好。你只需要在 MarkInvalid 之前加上 ClearInvalid ,如lost_bits1110所指出的那样:

Validation.ClearInvalid((BindingExpressionBase)error.BindingInError);
Validation.MarkInvalid((BindingExpressionBase)error.BindingInError, error);