4

我已经成功创建了一个文本框,该文本框根据其模型/虚拟机中设置的验证规则显示/折叠错误消息。对于 ex. 的电子邮件,代码如下所示:

    <StackPanel Grid.Row="3" Grid.Column="1">
        <TextBox MaxLength="200" x:Name="mailTextBox"
                Style="{StaticResource SectionEditPropertyTextBox}"
                Text="{Binding Email, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
        <ContentPresenter Visibility="{Binding ElementName=mailTextBox, Path=(Validation.HasError), Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=True }"
                Content="{Binding ElementName=mailTextBox, Path=(Validation.Errors).CurrentItem}"
                HorizontalAlignment="Left">
            <ContentPresenter.ContentTemplate>
                <DataTemplate>
                    <Label Style="{StaticResource SectionEditErrorLabel}" Content="{Binding Path=ErrorContent}"/>
                </DataTemplate>
            </ContentPresenter.ContentTemplate>
        </ContentPresenter>
    </StackPanel>

由于我有很多这些,我希望将所有这些都放在一个控制模板中,并将其重新定位到一个公共资源文件中。

我的模板如下所示:

<ControlTemplate x:Key="FormTextBox" TargetType="{x:Type TextBox}">
    <StackPanel Grid.Row="{TemplateBinding Grid.Row}" Grid.Column="{TemplateBinding Grid.Column}">
        <TextBox x:Name="validableText" MaxLength="{TemplateBinding MaxLength}"
                Style="{StaticResource SectionEditPropertyTextBox}"
                Text="{TemplateBinding Text}" />
        <ContentPresenter Visibility="{Binding ElementName=validableText, Path=(Validation.HasError), Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=True }"
                Content="{Binding ElementName=validableText, Path=(Validation.Errors).CurrentItem}"
                HorizontalAlignment="Left">
            <ContentPresenter.ContentTemplate>
                <DataTemplate>
                    <Label Style="{StaticResource SectionEditErrorLabel}" Content="{Binding Path=ErrorContent}"/>
                </DataTemplate>
            </ContentPresenter.ContentTemplate>
        </ContentPresenter>
    </StackPanel>
</ControlTemplate>

我像这样链接到它:

    <TextBox Grid.Row="3" Grid.Column="1" MaxLength="200" Template="{StaticResource FormTextBox}"
             Text="{Binding Email, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />

不幸的是,它不执行任何验证,因此必须以某种方式破坏绑定......

请指教...

谢谢。

4

1 回答 1

5

您不需要模板 StackPanel 中的Grid.Rowand绑定,因为无论如何都不会是 a 的直接子代,Grid.ColumnStackPanelGrid

TemplateBinding始终是一个OneWay绑定,因此TextTemplated 的属性TextBox永远不会更新。将其更改为使用RelativeSource和的常规绑定TwoWay

更改ElementName=validableTextRelativeSource={RelativeSource TemplatedParent}in bindings forContentPresenter因为我们要对 TemplatedTextBox而不是TextBoxTemplate 内部执行验证检查。

<ControlTemplate x:Key="FormTextBox" TargetType="{x:Type TextBox}">
    <StackPanel>
        <TextBox x:Name="validableText"
                 MaxLength="{TemplateBinding MaxLength}"
                 Style="{StaticResource SectionEditPropertyTextBox}"
                 Text="{Binding RelativeSource={RelativeSource TemplatedParent},
                                Path=Text,
                                Mode=TwoWay,
                                UpdateSourceTrigger=PropertyChanged}" />
        <ContentPresenter Visibility="{Binding RelativeSource={RelativeSource TemplatedParent},
                                               Path=(Validation.HasError),
                                               Converter={StaticResource BooleanToVisibilityConverter}
                                               ConverterParameter=True}"
                            Content="{Binding RelativeSource={RelativeSource TemplatedParent},
                                              Path=(Validation.Errors).CurrentItem}"
                            HorizontalAlignment="Left">
            <ContentPresenter.ContentTemplate>
                <DataTemplate>
                    <Label Style="{StaticResource SectionEditErrorLabel}" Content="{Binding Path=ErrorContent}"/>
                </DataTemplate>
            </ContentPresenter.ContentTemplate>
        </ContentPresenter>
    </StackPanel>
</ControlTemplate>

附带说明一下,您在此处拥有的另一种选择是使用您拥有UserControl的原始 Xaml 片段创建一个。您可以引入场景所需的依赖属性(文本等)。它只需要很小的改动。

于 2011-08-17T23:09:58.583 回答