Benjin
Benjin

Reputation: 2409

Simple way to change appearance of a TextBlock on hover?

I'm making a zoom control (Slider) with a TextBlock indicator that tells you want the current scale factor is (kinda like in the bottom-right corner of Word).

I'm a couple days into learning WPF, and I've been able to figure out how to do most of it, but I get the sense there's a much simpler way (one which, perhaps, only involves XAML-side code rather than a bunch of mouse events being captures.

I'd like for a the text to be underlined when hovered over (to imply clickability) and for a click to reset the slider element to 1.0.

Here's what I have:

<StatusBarItem Grid.Column="1" HorizontalAlignment="Right">
    <Slider x:Name="mapCanvasScaleSlider" Width="150" Value="1" Orientation="Horizontal" HorizontalAlignment="Left" 
            IsSnapToTickEnabled="True" Minimum="0.25"  Maximum="4" TickPlacement="BottomRight" 
            Ticks="0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4"/>
</StatusBarItem>
<StatusBarItem Grid.Column="2">
    <TextBlock Name="zoomIndicator" Text="{Binding ElementName=mapCanvasScaleSlider,Path=Value,StringFormat=0%}"
                MouseDown="ResetZoomWindow" MouseEnter="zoomIndicator_MouseEnter"  MouseLeave="zoomIndicator_MouseLeave"
                ToolTip="Zoom level; click to reset"/>
</StatusBarItem>

 

    private void ResetZoomWindow(object sender, MouseButtonEventArgs args)
    {
        mapCanvasScaleSlider.Value = 1.0;
    }

    private void zoomIndicator_MouseLeave(object sender, MouseEventArgs e)
    {
        zoomIndicator.TextDecorations = TextDecorations.Underline;
    }

    private void zoomIndicator_MouseLeave(object sender, MouseEventArgs e)
    {
        zoomIndicator.TextDecorations = null;
    }

I feel as though there's a better way to do this through XAML rather than to have three separate .cs-side functions.

Upvotes: 1

Views: 1448

Answers (3)

McGarnagle
McGarnagle

Reputation: 102753

Typically, you wouldn't want to use a TextBlock as a button (although of course you can). You may want to consider using a more appropriate control like Button or HyperlinkButton, which have the basic mouse event handling already wired up. You can then apply whatever styles you like. A Button control, for example, can be easily styled re-templated as a TextBlock with underline on mouse-over:

<Style TargetType="Button" x:Key="LinkButtonStyle">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="MouseOver">
                                <Storyboard Duration="0:0:0.1">
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="content" Storyboard.TargetProperty="TextDecorations">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <TextDecorationCollection>Underline</TextDecorationCollection>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <TextBlock x:Name="content" Text="{TemplateBinding Content}" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Use it by referencing the style key:

<Button Content="click" Style="{StaticResource LinkButtonStyle}" />

Using this approach (rather than the alternative of adding triggers to a TextBlock) brings some advantages, which are built in to the Button control.

  1. You can apply styles to compound states like Pressed
  2. You can use the Click event, and its related Command property

Upvotes: 0

michalczukm
michalczukm

Reputation: 10459

You can use VisualState (if you're using Blend its easy to edit). Personally I prefer style triggers, unless I have to add StoryBoard animation - then I offen use VisualState

about VisualState

Upvotes: 0

Klee
Klee

Reputation: 2032

You could use a style trigger for the text block, like described in this other post How to set MouseOver event/trigger for border in XAML?

Working solution:

<StatusBarItem Grid.Column="2">
    <TextBlock Name="zoomIndicator" Text="{Binding ElementName=mapCanvasScaleSlider,Path=Value,StringFormat=0%}"
                MouseDown="ResetZoomWindow" ToolTip="Zoom level; click to reset">
        <TextBlock.Style>
            <Style>
                <Setter Property="TextBlock.TextDecorations" Value="" />
                <Style.Triggers>
                    <Trigger Property="TextBlock.IsMouseOver" Value="True">
                        <Setter Property="TextBlock.TextDecorations" Value="Underline" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
</StatusBarItem>

Still have to reset the zoom level manually (I think), though.

Upvotes: 1

Related Questions