Bhaclash
Bhaclash

Reputation: 3

How to specify a DependencyProperty as a resource

I'd like to create buttons programmatically in WPF which grows to a specific size when IsMouseOver == true, and shrink to its original size when IsMouseOver == false.

To achieve this behaviour, I derived the Button class, and added a DependencyProperty:

public class ScalableButton : Button
{
    public Storyboard MouseOutAnimation
    {
        get { return (Storyboard)GetValue(MouseOutAnimationProperty); }
        set { SetValue(MouseOutAnimationProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MouseOutAnimation.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MouseOutAnimationProperty =
        DependencyProperty.Register("MouseOutAnimation", typeof(Storyboard), typeof(ScalableButton), new UIPropertyMetadata(null));

    public ScalableButton(double originalScale, Style style)
        : base()
    {
        CreateMouseOutAnimation(originalScale);
        RenderTransform = new ScaleTransform(originalScale, 1, 0.5, 0.5);
        RenderTransformOrigin = new Point(0.5, 0.5);
        Style = style;
        ApplyTemplate();
    }

    private void CreateMouseOutAnimation(double originalScale)
    {
        DoubleAnimation animX = new DoubleAnimation();
        animX.To = originalScale;
        animX.Duration = TimeSpan.FromMilliseconds(200);
        DoubleAnimation animY = new DoubleAnimation();
        animY.To = 1;
        animY.Duration = TimeSpan.FromMilliseconds(200);
        Storyboard sb = new Storyboard();
        sb.Children.Add(animX);
        sb.Children.Add(animY);
        Storyboard.SetTarget(sb, this.RenderTransform);
        Storyboard.SetTargetProperty(animX, new PropertyPath(ScaleTransform.ScaleXProperty));
        Storyboard.SetTargetProperty(animY, new PropertyPath(ScaleTransform.ScaleYProperty));
        MouseOutAnimation = sb;
    }
}

Then, I created a Style with a ControlTemplate to make a custom appearance for my buttons, and added a Storyboard resource to scale up them, and another to scale down and here is the problem:

<Style TargetType="{x:Type rgw:ScalableButton}" x:Key="EllipseWithText" >
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type rgw:ScalableButton}">
                <ControlTemplate.Resources>
                    <Storyboard x:Key="MouseOverAnimation">
                        <DoubleAnimation Storyboard.TargetName="ButtonGrid" Storyboard.TargetProperty="RenderTransform.ScaleX" To="1.2" Duration="0:0:1" />
                        <DoubleAnimation Storyboard.TargetName="ButtonGrid" Storyboard.TargetProperty="RenderTransform.ScaleY" To="1.2" Duration="0:0:1" />
                    </Storyboard>
                    <Storyboard x:Key="MouseOutAnimation">
                        <!-- This would be the one which scales down -->
                    </Storyboard>
                </ControlTemplate.Resources>
                <Grid x:Name="ButtonGrid" RenderTransform="{TemplateBinding RenderTransform}" RenderTransformOrigin="0.5, 0.5">
                    <Ellipse x:Name="ButtonEllipse" Height="50" Width="150" Fill="#00000000" StrokeThickness="1" Stroke="Black" />
                    <TextBlock x:Name="ButtonText" Width="150" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverAnimation}" />
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOutAnimation}" />
                        </Trigger.ExitActions>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

So, how can I specify the ScalableButton.MouseOutAnimation as a resource?

Or is there any other way the achieve the scalable button?

Upvotes: 0

Views: 332

Answers (1)

Clemens
Clemens

Reputation: 128098

There is no need for a derived Button.

Do not set the To property in the ExitActions animations. This will automatically animate from the current property values back to the original property values. Note that in the example below i initiallly set ScaleX = 0.5.

<Style TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid RenderTransformOrigin="0.5, 0.5">
                    <Grid.RenderTransform>
                        <ScaleTransform x:Name="scale" ScaleX="0.5"/>
                    </Grid.RenderTransform>
                    <Ellipse Height="50" Width="150" Fill="Transparent" StrokeThickness="1" Stroke="Black" />
                    <TextBlock Width="150" HorizontalAlignment="Center" VerticalAlignment="Center"
                               TextAlignment="Center" TextWrapping="Wrap" Text="{TemplateBinding Content}"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetName="scale"
                                        Storyboard.TargetProperty="ScaleX"
                                        To="1.2" Duration="0:0:0.3"/>
                                    <DoubleAnimation Storyboard.TargetName="scale"
                                        Storyboard.TargetProperty="ScaleY"
                                        To="1.2" Duration="0:0:0.3"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetName="scale"
                                        Storyboard.TargetProperty="ScaleX"
                                        Duration="0:0:0.2"/>
                                    <DoubleAnimation
                                        Storyboard.TargetName="scale"
                                        Storyboard.TargetProperty="ScaleY"
                                        Duration="0:0:0.2"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.ExitActions>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

EDIT: Although MinWidth is certainly not a scale factor: you could bind like the following.

<ScaleTransform ScaleX="{Binding MinWidth,
    RelativeSource={RelativeSource Mode=TemplatedParent}}"/>

Upvotes: 1

Related Questions