Home > Enterprise >  Using a control style, how can you bind or trigger a change to ToolTip contents based on ToggleButto
Using a control style, how can you bind or trigger a change to ToolTip contents based on ToggleButto

Time:04-02

I have a shared ToggleButton style defined that shows one image when IsChecked is true, and a different image when IsChecked is false. Binding IsChecked to a boolean property on the ViewModel works fine to show the desired image, so I know that my style is being applied and the DataTrigger bound to IsChecked works.

I would like to change the ToolTip text when IsChecked changes, but I'm having quite a bit of trouble getting that to work. Ideally I'd like the ToolTip to say something like "Turn On" when unchecked and "Turn Off" when checked.

The issue is that the ToolTip is not connected to the ToggleButton in the visual tree, so I need another way to find the ToggleButton.IsChecked. I'm trying to do this entirely in a style, because I've got quite a lot of these buttons scattered around, so no changes to the VMs are permitted.

Ideally the solution would allow me to use the ToggleButton.Tag to store the text, and apply a Converter and StringFormat (or ContentStringFormat). I've already overridden the ContentTemplate and replaced it with a barebones ContentPresenter to get rid of the typical ToggleButton effects, so it can be changed further if necessary. (And maybe I've removed something important for this to work? idk.)

Here is my style that works to change image, but the ToolTip never changes.

<!--Toggle button where content is a switch image that's "On" when checked and "Off" when anything else-->
<Style TargetType="ToggleButton" x:Key="OnOffToggleButton" x:Shared="False">
    <!-- this worked to format the initial tooltip contents, but no way to bind.
    <Style.Resources> 
        <Style TargetType="ToolTip">
            <Setter Property="ContentStringFormat" Value="Turn on {0}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding ???}" Value="True">
                    <Setter Property="ContentStringFormat" Value="Turn off {0}"/>
                </DataTrigger> 
            </Style.Triggers>
        </Style>
    </Style.Resources> -->
    <Setter Property="Content" Value="{StaticResource ToggleOffImage}"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ToggleButton">
                <ContentPresenter>
                    <ContentPresenter.ToolTip>
                        <TextBlock>
                            <TextBlock.Style>
                                <Style TargetType="TextBlock">
                                    <!-- this works -->
                                    <Setter Property="Text" Value="{Binding Tag, RelativeSource={RelativeSource Self}, StringFormat=Turn on {0}}"/>
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding IsChecked}" Value="True">
                                            <!-- trigger has no effect -->
                                            <Setter Property="Text" Value="{Binding Tag, RelativeSource={RelativeSource Self}, StringFormat=Turn off {0}}"/>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </TextBlock.Style>
                        </TextBlock>
                    </ContentPresenter.ToolTip>
                </ContentPresenter>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource Self}}" Value="True">
            <Setter Property="Content" Value="{StaticResource ToggleOnImage}"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="ToolTip">
                <Setter.Value>
                    <!-- another thing that does not work -->
                    <TextBlock Text="{Binding Tag, RelativeSource={RelativeSource Self}, StringFormat=Turn off {0}}" />
                </Setter.Value>
            </Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

The buttons themselves are defined similar to this:

<ToggleButton Style="{StaticResource OnOffToggleButton}" 
              IsChecked="{Binding IsPoweredOn, Mode=OneWay}" 
              Command="{Binding TogglePowerCommand}" 
              Tag="Device Power"/>

CodePudding user response:

The StringFormat does not work with a ToolTip, as it can contain arbitrary content of type object, not just plain text. However, the ToolTip exposes a property ContentStringFormat that you can use.

Gets or sets a composite string that specifies how to format the Content property if it is displayed as a string.

Since a ToolTip is hosted in a separate popup window, it is not part of the same visual tree as the ToggleButton, but you can refer to it using the PlacementTarget of the ToolTip.

Gets or sets the UIElement relative to which the ToolTip is positioned when it opens.

<Style TargetType="ToggleButton" x:Key="OnOffToggleButton" x:Shared="False">
   <Setter Property="Content" Value="{StaticResource ToggleOffImage}"/>
   <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
   <Setter Property="ToolTip">
      <Setter.Value>
         <ToolTip Content="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"
                  ContentStringFormat="Turn on {0}">
         </ToolTip>
      </Setter.Value>
   </Setter>
   <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ToggleButton">
                <ContentPresenter/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
   <Style.Triggers>
        <DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource Self}}" Value="True">
            <Setter Property="Content" Value="{StaticResource ToggleOnImage}"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="ToolTip">
               <Setter.Value>
                  <ToolTip Content="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"
                           ContentStringFormat="Turn off {0}">
                  </ToolTip>
               </Setter.Value>
            </Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

A converter can still be applies in the Content binding as usual.

<ToolTip Content="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}, Converter={StaticResource YourConverter}}"
         ContentStringFormat="Turn on {0}">
  • Related