wpfbuttontriggerssettercontroltemplate

How to set some value to a parent control template property by clicking on button inside this template?


I want to implement some custom Search TextBox with a loop icon and placeholder. So I created a custom Control Template where there is TextBlock for the loop icon (I used some symbols from specific fonts), ScrollViewer (it's a default control from the default TextBox template which displays a text), TextBlock with some text "Search" as placeholder (which is invisible when my TextBox go focus or user writes something) and Button (which is invisible when TextBox is empty and visible when user writes something, should clear text of TextBox on click). Here is how it looks:

enter image description here

Here is the code of this Control Template:

<ControlTemplate x:Key="SearchTextBoxTemplate" TargetType="{x:Type TextBox}">
    <Border Background="{TemplateBinding Background}"
            BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}"
            CornerRadius="5"
            SnapsToDevicePixels="True">
        <Grid HorizontalAlignment="Stretch"
              VerticalAlignment="Stretch">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock Margin="6,1,6,0"
                       Grid.Column="0"
                       FontFamily="{Binding Font, Source={StaticResource Icons}}"
                       FontSize="{TemplateBinding FontSize}"
                       Foreground="#8C8C8C"
                       FontWeight="Normal"
                       Text="&#xE71E;"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"/>
            <TextBlock x:Name="Placeholder"
                       Grid.Column="1"
                       FontSize="{TemplateBinding FontSize}"
                       Focusable="False"
                       Text="Search"
                       Foreground="#AAAFB4"
                       IsHitTestVisible="False"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"
                       Visibility="Collapsed"/>
            <ScrollViewer x:Name="PART_ContentHost"
                          Grid.Column="1"
                          Focusable="False"
                          HorizontalScrollBarVisibility="Hidden"
                          VerticalScrollBarVisibility="Hidden"
                          VerticalContentAlignment="Center"
                          VerticalAlignment="Center"/>
            <Button x:Name="ClearSearchText"
                    Margin="5,0,6,0"
                    Grid.Column="2"
                    Background="Transparent"
                    BorderBrush="Transparent"
                    BorderThickness="0"
                    Cursor="Hand"
                    FontFamily="{Binding Font, Source={StaticResource ResourceKey=Icons}}"
                    HorizontalAlignment="Right"
                    VerticalAlignment="Center">
                <Button.Content>
                    <Grid>
                        <TextBlock FontSize="12"
                                   Foreground="#D1D1D1"
                                   Text="&#xE91F;"/>
                        <TextBlock FontSize="8"
                                   HorizontalAlignment="Center"
                                   VerticalAlignment="Center"
                                   Foreground="White"
                                   Text="&#xE711;"/>
                    </Grid>
                </Button.Content>
            </Button>
        </Grid>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="Opacity" Value="0.6"/>
        </Trigger>
        <Trigger Property="Text" Value="{x:Static sys:String.Empty}">
            <Setter TargetName="ClearSearchText" Property="Visibility" Value="Collapsed"/>
        </Trigger>
        <Trigger Property="Text" Value="{x:Null}">
            <Setter TargetName="ClearSearchText" Property="Visibility" Value="Collapsed"/>
        </Trigger>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsKeyboardFocusWithin" Value="False"/>
                <Condition Property="Text" Value="{x:Static sys:String.Empty}"/>
            </MultiTrigger.Conditions>
            <Setter TargetName="Placeholder" Property="Visibility" Value="Visible"/>
        </MultiTrigger>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsKeyboardFocusWithin" Value="False"/>
                <Condition Property="Text" Value="{x:Null}"/>
            </MultiTrigger.Conditions>
            <Setter TargetName="Placeholder" Property="Visibility" Value="Visible"/>
        </MultiTrigger>
        <Trigger SourceName="ClearSearchText" Property="IsPressed" Value="True">
            <Setter Property="Text" Value="{x:Null}"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Everything works fine. However, I am still unable to write a correct logic that should clear Text of TextBox by clicking on the Button. I want to do that here in the template in XAML without adding some new backend code or creating custom user controls.

As you can see at the end of ControlTemplate.Triggers group I tried to add one more trigger to clear Text if the Button was pressed. But it doesn't work:

<Trigger SourceName="ClearSearchText" Property="IsPressed" Value="True">
    <Setter Property="Text" Value="{x:Null}"/>
</Trigger>

Also, I tried to add a checking of the same Button property to Button style:

<Button>
    <Button.Style>
        <Style TargetType="{x:Type Button}">
            <Style.Triggers>
                <Trigger Property="IsPressed" Value="True">
                    .... Some setter
                </Trigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

But here is I don't know how to correctly get a Text property from the parent Control Template where this Button is placed inside.

So how to do this correctly and how to clear Text by clicking on Button?


Solution

  • Using EventTrigger and ChangePropertyAction of Microsoft.Xaml.Behaviors.Wpf, you can set TextBox.Text property when Button.Click event is fired.

    <Button x:Name="ClearSearchText"
            ...>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <i:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource AncestorType={x:Type TextBox}}}"
                                        PropertyName="Text" Value="{x:Null}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
    

    As a side note, if the target were TextBlock.Text property, you could also use normal EventTrigger and StringAnimationUsingKeyFrames. But it won't work for TextBox.Text property because it is not animatable.