Beetlejuice
Beetlejuice

Reputation: 4425

WPF animation does not work

I created a spinner control, like one below, but when using in a windows opened with win.Show() command, the animation does not work.

My code to open this windows is:

win = new WaitWindow("wait...");
win.Show();

//do some long processing

win.Close();

It looks like the window thread gets frozen.

What I can do?

This is the spinner control:

<UserControl.Resources>
<Color x:Key="FilledColor" A="255" B="155" R="155" G="155"/>
<Color x:Key="UnfilledColor" A="0" B="155" R="155" G="155"/>

<Style x:Key="BusyAnimationStyle" TargetType="Control">
    <Setter Property="Background" Value="#7F000000"/>

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Control">
                <ControlTemplate.Resources>
                    <Storyboard x:Key="Animation0" BeginTime="00:00:00.0" RepeatBehavior="Forever">
                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipse0" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00.0" Value="{StaticResource FilledColor}"/>
                            <SplineColorKeyFrame KeyTime="00:00:01.6" Value="{StaticResource UnfilledColor}"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>

                    <Storyboard x:Key="Animation1" BeginTime="00:00:00.2" RepeatBehavior="Forever">
                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00.0" Value="{StaticResource FilledColor}"/>
                            <SplineColorKeyFrame KeyTime="00:00:01.6" Value="{StaticResource UnfilledColor}"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>

                    <Storyboard x:Key="Animation2" BeginTime="00:00:00.4" RepeatBehavior="Forever">
                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipse2" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00.0" Value="{StaticResource FilledColor}"/>
                            <SplineColorKeyFrame KeyTime="00:00:01.6" Value="{StaticResource UnfilledColor}"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>

                    <Storyboard x:Key="Animation3" BeginTime="00:00:00.6" RepeatBehavior="Forever">
                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipse3" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00.0" Value="{StaticResource FilledColor}"/>
                            <SplineColorKeyFrame KeyTime="00:00:01.6" Value="{StaticResource UnfilledColor}"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>

                    <Storyboard x:Key="Animation4" BeginTime="00:00:00.8" RepeatBehavior="Forever">
                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipse4" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00.0" Value="{StaticResource FilledColor}"/>
                            <SplineColorKeyFrame KeyTime="00:00:01.6" Value="{StaticResource UnfilledColor}"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>

                    <Storyboard x:Key="Animation5" BeginTime="00:00:01.0" RepeatBehavior="Forever">
                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipse5" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00.0" Value="{StaticResource FilledColor}"/>
                            <SplineColorKeyFrame KeyTime="00:00:01.6" Value="{StaticResource UnfilledColor}"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>

                    <Storyboard x:Key="Animation6" BeginTime="00:00:01.2" RepeatBehavior="Forever">
                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipse6" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00.0" Value="{StaticResource FilledColor}"/>
                            <SplineColorKeyFrame KeyTime="00:00:01.6" Value="{StaticResource UnfilledColor}"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>

                    <Storyboard x:Key="Animation7" BeginTime="00:00:01.4" RepeatBehavior="Forever">
                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="ellipse7" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00.0" Value="{StaticResource FilledColor}"/>
                            <SplineColorKeyFrame KeyTime="00:00:01.6" Value="{StaticResource UnfilledColor}"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                </ControlTemplate.Resources>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsVisible" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource Animation0}" x:Name="Storyboard0" />
                            <BeginStoryboard Storyboard="{StaticResource Animation1}" x:Name="Storyboard1"/>
                            <BeginStoryboard Storyboard="{StaticResource Animation2}" x:Name="Storyboard2"/>
                            <BeginStoryboard Storyboard="{StaticResource Animation3}" x:Name="Storyboard3"/>
                            <BeginStoryboard Storyboard="{StaticResource Animation4}" x:Name="Storyboard4"/>
                            <BeginStoryboard Storyboard="{StaticResource Animation5}" x:Name="Storyboard5"/>
                            <BeginStoryboard Storyboard="{StaticResource Animation6}" x:Name="Storyboard6"/>
                            <BeginStoryboard Storyboard="{StaticResource Animation7}" x:Name="Storyboard7"/>
                        </Trigger.EnterActions>

                        <Trigger.ExitActions>
                            <StopStoryboard BeginStoryboardName="Storyboard0"/>
                            <StopStoryboard BeginStoryboardName="Storyboard1"/>
                            <StopStoryboard BeginStoryboardName="Storyboard2"/>
                            <StopStoryboard BeginStoryboardName="Storyboard3"/>
                            <StopStoryboard BeginStoryboardName="Storyboard4"/>
                            <StopStoryboard BeginStoryboardName="Storyboard5"/>
                            <StopStoryboard BeginStoryboardName="Storyboard6"/>
                            <StopStoryboard BeginStoryboardName="Storyboard7"/>
                        </Trigger.ExitActions>
                    </Trigger>
                </ControlTemplate.Triggers>

                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                    <Grid>
                    <Canvas Height="60" Width="60">
                        <Canvas.Resources>
                            <Style TargetType="Ellipse">
                                <Setter Property="Width" Value="15"/>
                                <Setter Property="Height" Value="15" />
                                <Setter Property="Fill" Value="#009B9B9B" />
                            </Style>
                        </Canvas.Resources>

                        <Ellipse x:Name="ellipse0" Canvas.Left="1.75" Canvas.Top="21"/>
                        <Ellipse x:Name="ellipse1" Canvas.Top="7" Canvas.Left="6.5"/>
                        <Ellipse x:Name="ellipse2" Canvas.Left="20.5" Canvas.Top="0.75"/>
                        <Ellipse x:Name="ellipse3" Canvas.Left="34.75" Canvas.Top="6.75"/>
                        <Ellipse x:Name="ellipse4" Canvas.Left="40.5" Canvas.Top="20.75" />
                        <Ellipse x:Name="ellipse5" Canvas.Left="34.75" Canvas.Top="34.5"/>
                        <Ellipse x:Name="ellipse6" Canvas.Left="20.75" Canvas.Top="39.75"/>
                        <Ellipse x:Name="ellipse7" Canvas.Top="34.25" Canvas.Left="7" />
                        <Ellipse Width="39.5" Height="39.5" Canvas.Left="8.75" Canvas.Top="8" Visibility="Hidden"/>
                    </Canvas>
                        <Label Content="{Binding Path=Text}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
</UserControl.Resources>
<Control Style="{StaticResource BusyAnimationStyle}"/>

update

my windows control looks like: Note: using win.ShowDialog(), works, but the remaining process not run while windows is open.

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <local:Spinner Grid.Column="0" Width="16" Height="16" Margin="8,4,4,4" />
    <TextBlock Grid.Column="1" Name="MessageControl" VerticalAlignment="Center" Margin="8" />
</Grid>

Upvotes: 0

Views: 321

Answers (3)

Netstep
Netstep

Reputation: 522

This is because you doing long action in the UI thread, use another thread instead, here is an example:

var win = new WaitWindow();
Task.Factory.StartNew(() =>
{
    try
    {
        //do some long processing
        Thread.Sleep(1000);
    }
    finally
    {
        win.Dispatcher.Invoke(() => { win.Close(); });
    }
});
win.Show();

Upvotes: 1

Clemens
Clemens

Reputation: 128013

You may use Task.Run to start the long running action. However, instead of closing the Window from a Dispatcher action inside the Task action, you may just await the Task (from within a method that is marked as async):

Assuming there is some event handler that starts the processing:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    var win = new WaitWindow("wait...");
    win.Show();

    await Task.Run(() =>
    {
       // do some long processing
    });

    win.Close();
}

Upvotes: 2

grek40
grek40

Reputation: 13438

You can use Task.Run and ContinueWith to load your work into a task and close the window when the task ended (note I don't check for task-success here).

var win = new WaitWindow("wait...");
win.Show();

Task.Run(() =>
{
    //do some long processing
    ProcessSomething();
}).ContinueWith(t =>
{
    Dispatcher.Invoke(() => win.Close());
});

Upvotes: 0

Related Questions