3

I'm using a button where I've shaped it, in its ControlTemplate. I've also added a storyboard in the controlTemplate. The storyboard changes the boarder of the element in my controlTemplate. I access this from the code behind and activate it, the problem is when I do this on the phone there is a lag. I've structured my code after the MVVM structure, my view is:

 <Button x:Name="Button1" BorderThickness="0" BorderBrush="Transparent">
        <Button.Template>
            <ControlTemplate x:Name="Control">
                <Path x:Name="Control2" Style="{StaticResource style_ColorButton}" Data="{Binding Data}" Fill="{StaticResource Background}">
                    <Path.Resources>
                        <Storyboard x:Name="StoryBoard1">
                            <ColorAnimation Storyboard.TargetName="Control2" Storyboard.TargetProperty="(Stroke).(SolidColorBrush.Color)" To="Blue" Duration="0"/>
                        </Storyboard>
                    </Path.Resources>
                </Path>
            </ControlTemplate> 
        </Button.Template>

And my the part of the ViewModel where I activate my storyboard:

   foreach (UIElement x in ElementsAtPoint)
        {
            f = x as FrameworkElement;
            if (f is Path)
            {
                try { 
                h = f as Path;
                Storyboard sb = h.Resources["StoryBoard1"] as Storyboard;
                sb.Begin();
                    }
                catch
                {

                }
                break;
            }
        }

I've read that one can use Dependency object for the animation, but I'm not sure how it works or if it will work, but any help trying to implement dependency object for the animation would be appreciated.

Community
  • 1
  • 1
JonasN89
  • 1,386
  • 2
  • 11
  • 23
  • a very important information is: when the animation is supposed to run. – lisp Mar 23 '14 at 09:58
  • two questions, why do you have two parts named "Control" and why/when are you trying to animate this? – Shawn Kendrot Mar 24 '14 at 19:10
  • @lisp When a user hovers above the button, I find the storyboard in the foreach loop and run the storyboard. – JonasN89 Mar 25 '14 at 11:01
  • @ShawnKendrot That was a mistake, only suppose to be one "control", changed it now. See above comment for the rest. – JonasN89 Mar 25 '14 at 11:03
  • @JonasN89 There is no "hover" in Windows Phone. What event (of which control) triggers the animation? – lisp Mar 25 '14 at 12:29
  • @lisp didn't know you wanted the event, I'm using an manipulationDeltaEvent, but it is not for the button, but for an item which i'm moving above the button – JonasN89 Mar 25 '14 at 12:50

1 Answers1

4

I would recommend using VisualStates to do what you are looking for. I modified the Style of a button to add a story to the MouseOver VisualState, then added event listeners for MouseEnter and MouseLeave to the button. These events are fired when you touch the device, and drag your finger over an element, and then drag it off again. You could modify the code below to check if something is being dragged. You could also take a look at Drag/Drop functionality.

Using the following Style

<Style x:Key="ButtonStyle" TargetType="Button">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
    <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
    <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMedium}"/>
    <Setter Property="Padding" Value="10,5,10,6"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid Background="Transparent">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Orange"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneButtonBasePressedForegroundBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}">
                        <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Notice it has a MouseOver VisualState. Then assign the style and subscribe to the event handlers

<Button Content="Drag over me" Style="{StaticResource ButtonStyle}"  MouseEnter="OnButtonMouseEnter" MouseLeave="OnButtonMouseLeave"/>

And in the event handler change the visual state.

private void OnButtonMouseEnter(object sender, MouseEventArgs e)
{
    VisualStateManager.GoToState((Control)sender, "MouseOver", true);
}

private void OnButtonMouseLeave(object sender, MouseEventArgs e)
{
    VisualStateManager.GoToState((Control)sender, "Normal", true);
}

With this, when you tap and drag your finger over the button, it will turn orange with white text.

Shawn Kendrot
  • 12,425
  • 1
  • 25
  • 41
  • Is there a way to change the visualState from my ViewModel instead of doing it from the code behind the xaml. I tried using binding, but get an error when I assign it to the mouseEnter nad MouseLeave – JonasN89 Mar 28 '14 at 08:49
  • There is nothing wrong with code being in your code behind. It is a UI specific thing you are trying to accomplish. You could create your own button class and in that class listen to the events. eg: `public class HoverButon : Button { public HoverButton() { /*subscribe to events*/ } /* event handlers */ } – Shawn Kendrot Mar 28 '14 at 13:29
  • I added the xam lto my buttons style and the code too, but nothing happens when I move over or leave the button. Is this because I've added the path to my control template? – JonasN89 Mar 29 '14 at 08:37
  • I modyfied what you posted, adding the path in the controlTemplate and aiming the storyboards at the stroke of the path. At the moment I've got 46 of these in a map, and when I move over there's a lag. Is there a way to avoid the lag when i Change the visualState? – JonasN89 Mar 29 '14 at 09:32