user14953869
user14953869

Reputation:

How to fix animation that appears to not be running while Button Click event is processing?

I'm using C# WPF and Blend for Visual Studio 2019. I have a button that will get data from a SQL Server database on click.

Also, the button has an animation in Blend that will run rotate OnPreviewMouseDown.

But the problem is when I click the button in one-moment animation is running but then it suddenly stops.

I think this problem is because of the button on Click event running some code and that prevents the animation from continuing.

Long story short: the animation for the button appears to not working when click event is processing.

in Blend :enter image description here

XAML :

<Window.Resources>
    <Storyboard x:Key="RotationBtn">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="Command4">
            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="720"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
<Window.Triggers>
    <EventTrigger RoutedEvent="UIElement.PreviewMouseDown" SourceName="Command4">
        <BeginStoryboard x:Name="RotationBtn_BeginStoryboard" Storyboard="{StaticResource RotationBtn}"/>
    </EventTrigger>
</Window.Triggers>

<Grid>
    <Button x:Name="Command4" Content="Next Stage" Margin="599,406,304,84"   Width="130" Height="37" FontSize="8" Click="Command4_Click" Background="#FFDDDDDD" BorderBrush="{x:Null}" RenderTransformOrigin="0.5,0.5">
        <Button.RenderTransform>
            <TransformGroup>
                <ScaleTransform/>
                    <SkewTransform/>
                        <RotateTransform/>
                            <TranslateTransform/>
            </TransformGroup>
        </Button.RenderTransform>
    </Button>
</Grid>

CS Code:

private void Command4_Click(object sender, RoutedEventArgs e)
{
    var MyQuery = dbms.Database.SqlQuery<DB_Cust>("SELECT * FROM Customers").ToList();
}

What have I tried :

First Try

private void Command4_Click(object sender, RoutedEventArgs e)
{
    Thread trd = new Thread(() =>
    {
        Dispatcher.Invoke((Action)(() =>
        {
            Storyboard sb = TryFindResource("RotationBtn") as Storyboard;
            Storyboard.SetTarget(sb, Command4 );
            sb.Begin();
        }));
    });
    var MyQuery = dbms.Database.SqlQuery<DB_Cust>("SELECT * FROM Customers").ToList();
}

Second Try

private void Command4_Click(object sender, RoutedEventArgs e)
{
    new Thread(() =>
    {
        App.Current.Dispatcher.Invoke((Action)delegate
        {
            Storyboard sb = TryFindResource("RotationBtn") as Storyboard;
            Storyboard.SetTarget(sb, Command4);
            sb.Begin();
        });
    }).Start();
    var MyQuery = dbms.Database.SqlQuery<DB_Cust>("SELECT * FROM Customers").ToList();
}

Upvotes: 0

Views: 350

Answers (2)

user14357390
user14357390

Reputation:

Try this :

 private void Command4_Click(object sender, RoutedEventArgs e)
        {
BackgroundWorker bgWorker = new BackgroundWorker ();
bgWorker.DoWorker += DoWorkEventHandler(bgWorker_DoWork);
        }
Private void bgWorker_DoWork(object sender, DoWorkEvent)
{
 Storyboard sb = TryFindResource("RotationBtn") as Storyboard;
                    //Storyboard.SetTarget(sb, ButtonRotate);
                    sb.Begin();
}

Upvotes: 0

EldHasp
EldHasp

Reputation: 7943

First, you forgot to start the thread:

        private void Command4_Click(object sender, RoutedEventArgs e)
        {

            Thread trd = new Thread(() =>
            {
                Dispatcher.Invoke((Action)(() =>
                {
                    Storyboard sb = TryFindResource("RotationBtn") as Storyboard;
                    Storyboard.SetTarget(sb, Command4);
                    sb.Begin();
                }));
            });
            trd.Start();
        }

Secondly, your animation starts from the current value of the rotation angle and continues up to 720 degrees.
But when you start the animation again, the angle is already equal to 720 and its animation to 720, accordingly, does not occur.
To start the animation from zero again, you need to set the first frame from zero.

        <Storyboard x:Key="RotationBtn">
            <DoubleAnimationUsingKeyFrames
                Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"
                Storyboard.TargetName="Command4">
                <EasingDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="720"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

But I would rather use a linear animation with relative displacement rather than frame-by-frame.
If, of course, this is acceptable for your task.

        <Storyboard x:Key="RotationBtn">
            <DoubleAnimation
                Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"
                Storyboard.TargetName="Command4"
                By="720"/>
        </Storyboard>

Thirdly, classes "Storyboard", "BeginStoryboard" and others are designed to make it easy to run animations from XAML.
When launched from Sharpe, they are not required.
Of course, they can be used in Sharpe, but there is little sense in this.

Also, in modern Sharp, the explicit creation of new flows is not accepted (only in very rare cases). Tasks are used for asynchronous execution.

<Window ---------------------------
        ---------------------------
        ---------------------------
        Height="600" Width="1700">
    <Window.Resources>
        <DoubleAnimation x:Key="Button.Rotate.Animation" By="720"/>
    </Window.Resources>
    <Grid>
        <Button x:Name="Command4" Content="Next Stage" Margin="599,406,304,84"
                Width="130" Height="37" FontSize="8" Click="Command4_Click"
                Background="#FFDDDDDD" BorderBrush="{x:Null}"
                RenderTransformOrigin="0.5,0.5">
            <Button.RenderTransform>
                <RotateTransform x:Name="ButtonRotate"/>
            </Button.RenderTransform>
        </Button>
    </Grid>
</Window>
        private void Command4_Click(object sender, RoutedEventArgs e)
        {

            Task.Run(() =>
            {
                Dispatcher.Invoke((Action)(() =>
                {
                    var animation = TryFindResource("Button.Rotate.Animation") as AnimationTimeline;
                    ButtonRotate.BeginAnimation(RotateTransform.AngleProperty, animation);
                }));
            });
        }

Fourth, you have an unnecessary target element assignment in the clicker.
The target is already specified in the XAML when the StoryBoard is declared. Also notice the double call of the animation.
The first time a key is pressed, the trigger animation is invoked in XAML.
The second time the key is released, the clicker animation is called.

    <Window.Resources>
        <Storyboard x:Key="RotationBtn">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Angle" Storyboard.TargetName="ButtonRotate">
                <EasingDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="720"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="UIElement.PreviewMouseDown" SourceName="Command4">
            <BeginStoryboard x:Name="RotationBtn_BeginStoryboard" Storyboard="{StaticResource RotationBtn}"/>
        </EventTrigger>
    </Window.Triggers>

    <Grid>

        <Button x:Name="Command4" Content="Next Stage"
                Margin="599,406,304,84" 
                Width="130" Height="37" FontSize="8"
                Click="Command4_Click" Background="#FFDDDDDD"
                BorderBrush="{x:Null}"
                RenderTransformOrigin="0.5,0.5">
            <Button.RenderTransform>
                <RotateTransform x:Name="ButtonRotate"/>
            </Button.RenderTransform>
        </Button>

    </Grid>
</Window>
        private void Command4_Click(object sender, RoutedEventArgs e)
        {
            new Thread(() =>
            {
                Dispatcher.Invoke((Action)delegate
                {
                    Storyboard sb = TryFindResource("RotationBtn") as Storyboard;
                    //Storyboard.SetTarget(sb, ButtonRotate);
                    sb.Begin();
                });
            }).Start();
        }

P.S. I didn't see your "Second Try". This is due to my carelessness.
My apologies to you.
But the rest of the points in my answer remain relevant.

Upvotes: 1

Related Questions