WPF自定义控件不显示验证错误

时间:2018-12-29 08:43:54

标签: wpf xaml

如果我通过自定义控件中的依赖项属性传输绑定,则不会显示验证错误。

详细信息

我有一个视图模型,该视图模型总是对一个属性存在验证错误

class ViewModel : IDataErrorInfo
{
    public string Value { get; set; }

    public string Error
    {
        get { return null; }
    }

    public string this[string columnName]
    {
        get { return "Error"; }
    }
}

和观看中的TextBox

<TextBox 
    Text="{Binding Value, 
        Mode=TwoWay, 
        UpdateSourceTrigger=PropertyChanged, 
        ValidatesOnDataErrors=True, 
        NotifyOnValidationError=True}" />

所以它将被红色边框包围。

ui picture

然后我创建了一个名为WrappedTextBox的自定义控件,其中包含一个Text依赖属性

class WrappedTextBox : Control
{
    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(
            "Text",
            typeof(string),
            typeof(WrappedTextBox));
}

和模板

<Style TargetType="local:WrappedTextBox">
    <Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:WrappedTextBox">
                <Grid>
                    <AdornerDecorator>
                        <TextBox
                            Text="{Binding Text, 
                                Mode=TwoWay, 
                                UpdateSourceTrigger=PropertyChanged, 
                                ValidatesOnDataErrors=True, 
                                NotifyOnValidationError=True, 
                                RelativeSource={RelativeSource Mode=TemplatedParent}}" />
                    </AdornerDecorator>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

将其放在视图上

<local:WrappedTextBox
    Text="{Binding Value, 
        Mode=TwoWay, 
        UpdateSourceTrigger=PropertyChanged, 
        ValidatesOnDataErrors=True, 
        NotifyOnValidationError=True}" />

如上图所示,第二个控件上没有红色边框。

如果我不删除Validation.ErrorTemplate中的WrappedTextBox,它将是

picture 2

如何在TextBox内的WrappedTextBox上显示错误模板?

1 个答案:

答案 0 :(得分:0)

据我所知,您的问题是IDataErrorInfo需要在您要绑定的类上实现,在您的ControlTemplate中,您要绑定到您的Text-Property WrappedTextBox,因此您的WrappedTextBox本身必须实现IDataErrorInfo才能对您的TextBox进行验证。

也请阅读此article,而不是创建新控件也可以做。

对于您要实现的目标,我想到了两个选择(注意:该选择是在您做更多事情的前提下创建的,因此前面提到的文章的选择不适用于您)

选项1 :直接从TextBox

派生

后面的代码:

class WrappedTextBox : TextBox
{

}

样式:

<Style TargetType="local:WrappedTextBox" BasedOn="{StaticResource {x:Type TextBox}}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <AdornerDecorator>
                    <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                        <ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
                    </Border>
                </AdornerDecorator>
                <-- ControlTemplate.Triggers etc. -->
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

用法:(与以前相同)

<local:WrappedTextBox
    Text="{Binding Value, 
        Mode=TwoWay, 
        UpdateSourceTrigger=PropertyChanged, 
        ValidatesOnDataErrors=True, 
        NotifyOnValidationError=True}" />

选项2 :通过Binding本身

后面的代码:

[TemplatePart(Name = "PART_TEXTBOX", Type = typeof(TextBox))]
class WrappedTextBox : Control
{
    private TextBox _partTextBox;

    private BindingBase _textBinding;
    public BindingBase TextBinding
    {
        get => _textBinding;
        set
        {
            if (_textBinding != value)
            {
                _textBinding = value;
                ApplyTextBinding();
            }
        }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        _partTextBox = base.GetTemplateChild("PART_TEXTBOX") as TextBox;
        ApplyTextBinding();
    }

    private void ApplyTextBinding()
    {
        if (_partTextBox != null)
            BindingOperations.SetBinding(_partTextBox, TextBox.TextProperty, _textBinding);
    }
}

样式:

<Style TargetType="local:WrappedTextBox">
    <Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:WrappedTextBox">
                <Grid>
                    <AdornerDecorator>
                        <TextBox x:Name="PART_TEXTBOX" />
                    </AdornerDecorator>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

用法:

<local:WrappedTextBox
    TextBinding="{Binding Value, 
        Mode=TwoWay, 
        UpdateSourceTrigger=PropertyChanged, 
        ValidatesOnDataErrors=True, 
        NotifyOnValidationError=True}" />