如何在控件模板中使用ElementName绑定?

15

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

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

"Cannot convert the value in attribute 'ElementName' to object of type 'System.String'. Object of type 'System.Windows.TemplateBindingExpression' cannot be converted to type 'System.String'. "

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

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

感谢您的帮助,

--- Shawn

以下是代码示例:

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

1
为什么不创建样式并将其应用于所有需要该样式的控件?为什么要在一个控件上定义某个属性,然后将其他控件绑定到它上面?这听起来最好很奇怪。 - Brent Stewart
@Brent 在 MS Access 表单开发中,将信息存储在标签属性中曾经是一种技术。这是一种廉价而肮脏的方法,用于将某些硬编码值传递给绑定到控件上某个属性/处理程序的 VBA 函数。在 WPF 中,我们不需要这样做,因为我们有更广泛的工具可供使用 =) - failedprogramming
@BrentStewart 这个实现的最终结果是使用 MVVM、绑定、数据模板等方法以列的形式显示信息。我专门缩小了我的示例以便在此网站上提问。我选择不使用 Grid 而是使用 WrapPanel 是因为我觉得它更容易和更清洁。我绑定一个 TextBlock 的多个属性到另一个 TextBlock 是因为我想让列的值复制我为其特定标题设置的属性(边距、宽度、对齐方式等)。如果每个 TextBlock 都会引用不同的 ElementName,您将如何使用样式来实现这一点? - Shawn Roser
1个回答

28

这似乎是一种有趣的模板方式,但它确实可以做到,你只需要在绑定时做得更加高级一些。

下面的代码可以工作,但我仍然认为这不是一个好的控件模板方式。

TextBlockTag 绑定到实际元素,然后在 ControlTemplate 中将 Tag 绑定到 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>

3
赞同指出这不是一个好的控件模板化方式。+1 - Brent Stewart
16
感谢您的回答。在我的应用程序中,它能按照我想要的方式工作。你和@BrentStewart都表示这不是模板控件的好方法。请问,在你看来,什么是一个好的方式,为什么这不是好的方法? - Shawn Roser
3
是的,没有其他选择,所以说“这不是一个好方法”有点儿可笑。显然,还有哪些选项可用?由于视觉树的设计方式,这种限制经常出现。 - user99999991

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接