Привязка WPF к родительскому свойству из вложенного элемента с помощью style

Я пытался создать текстовое поле с подсказкой, которая отображается, пока она пуста. У меня возникли проблемы с настройкой текста подсказки из стиля.

если быть точным, это работает (то есть, он правильно связывает):

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

Так в чем подвох? Как я могу привязаться к свойству ancestor из стиля?

2 ответов


проблема не в RelativeSource, а в том, как вы используете VisualBrush. Напомним, что стили являются общими для элементов, к которым вы их применяете. Причина, по которой ваш пример не работает, заключается в том, что вы пытаетесь поделиться одним текстовым полем (тем, которое вы отметили "внутренним") с несколькими родительскими текстовыми полями.

чтобы понять, почему это является проблемой, попробуйте мысленный эксперимент: внутреннее поле создается один раз (грубо говоря, это произойдет, когда стиль создан.) Какое из текстовых полей, к которым применяется стиль, должно быть выбрано в качестве предка внутреннего текстового поля при использовании привязки RelativeSource?

вот почему DataTemplates и ControlTemplates существует в WPF. Вместо того чтобы создавать экземпляры визуальных элементов напрямую, они определяют шаблон, позволяющий создавать несколько копий визуальных элементов по мере необходимости.


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>