WPF 控件模板中的嵌套绑定

发布于 2024-11-30 15:16:59 字数 2597 浏览 0 评论 0原文

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

    <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}" />

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

请告知...

谢谢。

I have successfully created a textbox that displays / collapses an error message depending upon a validation rule set in its model / vm. The code goes like this for the email for 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>

Since I have a bunch of these, I would have liked to put all of this in a control template and relocate this in a common resource file.

My template looks like this:

<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>

and I link to it like this:

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

Unfortunately, it doesn't perform any validation so the binding must be broken somehow...

Please advise...

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

知足的幸福 2024-12-07 15:16:59

您不需要模板 StackPanel 中的 Grid.RowGrid.Column 绑定,因为 StackPanel 不会是无论如何,

TemplateBinding 始终是 OneWay 绑定,因此模板化 TextBox< 的 Text 属性/code> 永远不会更新。将其更改为使用 RelativeSourceTwoWay 的常规绑定

ElementName=validableText 更改为 RelativeSource={RelativeSource TemplatedParent} ContentPresenter 的绑定,因为我们要对模板化 TextBox 而不是模板内的 TextBox 执行验证检查。

<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>

顺便说一下,这里的另一种选择是使用您拥有的原始 Xaml 片段创建一个 UserControl。您可以引入您的场景所需的依赖属性(文本等)。只需要进行一些小的更改。

You won't need the Grid.Row and Grid.Column bindings in the Template StackPanel since the StackPanel won't be the direct child of a Grid anyway,

TemplateBinding is always a OneWay binding so the Text property for the Templated TextBox will never get updated. Change it to a regular Binding with RelativeSource and TwoWay

Change ElementName=validableText to RelativeSource={RelativeSource TemplatedParent} in the bindings for ContentPresenter since we want to perform the validation check on the Templated TextBox and not the TextBox inside the Template.

<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>

On a side note, another alternative that you have here is to create a UserControl with the original piece of Xaml that you had. You could introduce the Dependency Properties needed for your scenario (Text etc.). It would only require small changes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文