1

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.

Benjin
  • 2,264
  • 2
  • 25
  • 50

3 Answers3

1

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.

Community
  • 1
  • 1
Klee
  • 2,022
  • 3
  • 23
  • 32
  • Seems to have done the trick. Better yet, I didn't even need to use a border! I'll edit your answer with the working code. – Benjin Jan 16 '14 at 21:37
0

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

michalczukm
  • 9,963
  • 6
  • 40
  • 47
0

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
McGarnagle
  • 101,349
  • 31
  • 229
  • 260