使用样式从嵌套元素中绑定到父属性的WPF问题

15

我一直在尝试构建一个带有提示的文本框,当文本框为空时显示提示。 但我在样式中设置提示文本时遇到了问题。

准确地说,这个有效(也就是它正确地绑定了):

    <TextBox Tag="hint text">
        <TextBox.Background>
            <VisualBrush Stretch="None">
                <VisualBrush.Visual>
                    <TextBlock Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=TextBox}}" FontStyle="Italic" Foreground="LightGray" />
                </VisualBrush.Visual>
            </VisualBrush>
        </TextBox.Background>
    </TextBox>

但是,当我将它移到样式中时,它就不起作用:

<Style TargetType="TextBox" x:Key="stlHintbox">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" Value="">
            <Setter Property="Background">
                <Setter.Value>
                    <VisualBrush Stretch="None">
                        <VisualBrush.Visual>
                            <TextBlock Tag="inner" Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=TextBox}}" 
                                       FontStyle="Italic" Foreground="LightGray" />
                        </VisualBrush.Visual>
                    </VisualBrush>
                </Setter.Value>
            </Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

<TextBox Tag="hint text" Style="{StaticResource stlHintbox}" />

那么问题来了?我怎么能从样式内部绑定到祖先属性呢?

2个回答

14
问题不在于RelativeSource,而在于您使用VisualBrush的方式。请记住,样式是在应用它们的元素之间共享的。您的示例无法正常工作的原因是,在实际效果中,您正在尝试将一个单独的文本框(您标记为“inner”的文本框)与多个父文本框共享。
为了看到这是一个问题,请进行一次思想实验:内部文本框被创建一次(粗略地说,这将在创建样式时发生)。当您使用RelativeSource绑定时,应选择哪个应用样式的文本框作为内部文本框的祖先?
这就是为什么WPF中存在DataTemplatesControlTemplates的原因。它们不是直接实例化可视化对象,而是定义了一个模板,允许根据需要创建多个可视化对象的副本。

好的,那真的讲得很有道理...看来我读书太快了 :) - veljkoz

5

Reativesource无法按预期工作。 最好使用控件模板创建水印文本框。但是您的版本也可以工作:

<Window.Resources>
    <Style TargetType="TextBox" x:Key="stlHintbox">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" Value="">
                <Setter Property="TextBox.Background">
                    <Setter.Value>
                        <VisualBrush Stretch="None" Visual="{Binding ElementName=hintText}"/>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<StackPanel>
    <TextBox Tag="hint text" x:Name="myTextBox" Style="{StaticResource stlHintbox}" />
    <Border Visibility="Hidden">
        <TextBlock x:Name="hintText" Text="{Binding Tag, ElementName=myTextBox}" FontStyle="Italic" Foreground="LightGray" />
    </Border>
</StackPanel>

这样做是可以的,但它会阻止我在同一个窗口中使用多个提示框,并且它的使用方式并不那么明显。感谢您对控件模板的建议,我会进一步研究它... - veljkoz

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