【问题标题】:How can I use an ElementName binding within a ControlTemplate?如何在 ControlTemplate 中使用 ElementName 绑定?
【发布时间】:2013-02-23 08:25:07
【问题描述】:

我有多个 TextBlock,它们在我的应用程序中引用不同的元素。直接在页面中使用时,我的代码可以正常工作。但是,我想创建一个 ControlTemplate 和一个 ContentControl 来减少代码的重复。

如何使用 TemplateBinding 将 ElementName 的引用从 ContentControl 传递到 ControlTemplate?以下代码抛出此错误:

"无法将属性 'ElementName' 中的值转换为对象类型 '系统.字符串'。类型的对象 'System.Windows.TemplateBindingExpression' 无法转换为类型 '系统.字符串'。 "

除了 Tag 属性之外,我还尝试了 ContentStringFormat ,但也没有用。

使用模板使其工作的正确方法是什么?

提前感谢您的帮助,

--- 肖恩

这是代码示例:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <Page.Resources>
        <ControlTemplate x:Key="MyTemplate" TargetType="{x:Type ContentControl}">
            <TextBlock Margin="{Binding ElementName={TemplateBinding Tag}, Path=Margin}" Text="{TemplateBinding Content}" TextAlignment="{Binding ElementName={TemplateBinding Tag}, Path=TextAlignment}" Width="{Binding ElementName={TemplateBinding Tag}, Path=Width}" />
        </ControlTemplate>
    </Page.Resources>
    <StackPanel>
        <TextBlock x:Name="AnotherElement" Margin="10" Text="Main TextBlock" TextAlignment="Center" Width="100" />
        <TextBlock x:Name="AnotherElement2" Margin="20" Text="Second TextBlock" TextAlignment="Left" Width="250" />
        <TextBlock Margin="{Binding ElementName=AnotherElement, Path=Margin}" Text="Here is my TextBlock!" TextAlignment="{Binding ElementName=AnotherElement, Path=TextAlignment}" TextTrimming="CharacterEllipsis" Width="{Binding ElementName=AnotherElement, Path=Width}" />
        <TextBlock Margin="{Binding ElementName=AnotherElement2, Path=Margin}" Text="Here is my Second TextBlock!" TextAlignment="{Binding ElementName=AnotherElement2, Path=TextAlignment}" TextTrimming="CharacterEllipsis" Width="{Binding ElementName=AnotherElement2, Path=Width}" />
        <ContentControl Content="Hello!" Tag="AnotherElement" Template="{StaticResource MyTemplate}" />
        <ContentControl Content="Hello Again!" Tag="AnotherElement2" Template="{StaticResource MyTemplate}" />
    </StackPanel>
</Page>

【问题讨论】:

  • 为什么不创建样式并将它们应用于所有需要该样式的控件?为什么要在一个控件上定义一些属性,然后将其他控件绑定到它?这听起来很奇怪。
  • @Brent 在 Tag 属性中存储信息曾经是 MS Access 表单开发的一种技术。将一些硬编码值传递给绑定到控件上的某些属性/处理程序的 VBA 函数是一种廉价而讨厌的方法。我们在 WPF 中不需要这个,因为我们可以使用更广泛的工具 =)
  • @BrentStewart 这个实现的最终结果是使用 MVVM、Bindings、DataTemplates 等在列中显示信息。我缩小了我的示例,专门用于在这个站点上询问。我选择不使用 Grid 而是使用 WrapPanel,因为我觉得使用起来更容易、更干净。我将一个 TextBlock 的多个属性绑定到另一个是因为我希望我的列值复制我为其特定标题设置的属性(边距、宽度、对齐方式等)。当每个文本块引用不同的元素名称时,您将如何使用样式来实现这一点?

标签: wpf xaml binding controltemplate


【解决方案1】:

这似乎是一种有趣的模板化方式,但它可以做到,你只需要对你的绑定有点花哨。

下面会起作用,但我仍然不认为这是模板化控件的好方法

TextBlock Tag 绑定到实际元素,然后在ControlTemplate 中将Tag 绑定到Tag 并使用其中的值,因为标签是元素,您可以使用其中的任何元素。

<Page.Resources>
    <ControlTemplate x:Key="MyTemplate" TargetType="{x:Type ContentControl}">
        <TextBlock Name="_this" Tag="{TemplateBinding Tag}" Margin="{Binding ElementName=_this, Path=Tag.Margin}" Text="{TemplateBinding Content}" TextAlignment="{Binding ElementName=_this, Path=Tag.TextAlignment}" Width="{Binding ElementName=_this, Path=Tag.Width}" />
    </ControlTemplate>
</Page.Resources>
<StackPanel>
    <TextBlock x:Name="AnotherElement" Margin="10" Text="Main TextBlock" TextAlignment="Center" Width="100" />
    <TextBlock x:Name="AnotherElement2" Margin="20" Text="Second TextBlock" TextAlignment="Left" Width="250" />
    <TextBlock Margin="{Binding ElementName=AnotherElement, Path=Margin}" Text="Here is my TextBlock!" TextAlignment="{Binding ElementName=AnotherElement, Path=TextAlignment}" TextTrimming="CharacterEllipsis" Width="{Binding ElementName=AnotherElement, Path=Width}" />
    <TextBlock Margin="{Binding ElementName=AnotherElement2, Path=Margin}" Text="Here is my Second TextBlock!" TextAlignment="{Binding ElementName=AnotherElement2, Path=TextAlignment}" TextTrimming="CharacterEllipsis" Width="{Binding ElementName=AnotherElement2, Path=Width}" />
    <ContentControl Content="Hello!" Tag="{Binding ElementName=AnotherElement}" Template="{StaticResource MyTemplate}" />
    <ContentControl Content="Hello Again!" Tag="{Binding ElementName=AnotherElement2}" Template="{StaticResource MyTemplate}" />
</StackPanel>

【讨论】:

  • +1 表示这不是模板化控件的好方法。
  • 感谢您的回答。这可以在我的应用程序中按我的意愿工作。您和@BrentStewart 都表示这不是模板化控件的好方法。在您的选择中,什么是好方法,为什么这不是一个?
  • 是的,没有其他选择,所以说“这不是一个好方法”有点愚蠢。显然,但还有哪些其他选项可用?由于视觉树的设计方式,这种限制经常出现。
猜你喜欢
  • 2010-09-18
  • 2023-04-08
  • 2012-07-14
  • 1970-01-01
  • 1970-01-01
  • 2012-03-09
  • 1970-01-01
  • 2014-02-25
  • 2018-11-08
相关资源
最近更新 更多