WPF Привязать к родительскому свойству из внутри вложенного элемента, используя стиль
Я пытаюсь создать текстовое поле с подсказкой, отображающей ее пустую.
У меня возникли проблемы с установкой текста подсказки из стиля.
Если быть точным, это работает (т.е. правильно связывается):
<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 из стиля?
Ответы
Ответ 1
Проблема не в RelativeSource, а в том, как вы используете VisualBrush. Напомним, что стили разделяются между элементами, к которым вы их применяете. Причина, по которой ваш пример не работает, заключается в том, что вы пытаетесь совместно использовать один текстовый блок (тот, который вы отметили "внутренним" ) несколькими родительскими текстовыми полями.
Чтобы понять, почему это проблема, попробуйте мысленный эксперимент. Внутреннее текстовое поле создается однажды (грубо говоря, это произойдет, когда будет создан стиль). Какое из текстовых полей, к которым применяется стиль, должно быть выбрано в качестве предка внутреннего текстового поля при использовании связывания RelativeSource?
Вот почему DataTemplates и ControlTemplates существуют в WPF, Вместо того, чтобы на самом деле создавать визуальные эффекты напрямую, они определяют шаблон, который позволяет создавать несколько копий визуальных изображений по мере необходимости.
Ответ 2
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>