2

My UI components are taking a while to load, I've tried as much as I can to reduce the loading time (and will probably give a few more things a go in future), but I've also introduced a 'busy' indicator to give the user some feedback.

However, I've found the animation stops when components are being loaded, making it pretty useless. I thought WPF had animation on a separate thread?

Here's what I mean, the loading indicator is behind the 'page' being loaded and unlaoded, so it only shows when one is removed. To demonstrate, I've added one that can be seen all the time to the side:

enter image description here

Is there anything I can do to run the storyboard animation in another thread?

It's part of the style, taken from the Material Design XAML toolkit (I've tried to pull out relevant info:

<Style x:Key="MaterialDesignLinearProgressBar" TargetType="{x:Type ProgressBar}">
 ...
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ProgressBar}">
            ...
                <Grid x:Name="TemplateRoot" RenderTransformOrigin="0,0.5" Opacity="0" Height="4">
                    <Grid.RenderTransform>
                        <TransformGroup>
                            <ScaleTransform ScaleX="0" ScaleY="0" />
                            <SkewTransform/>
                            <RotateTransform/>
                            <TranslateTransform/>
                        </TransformGroup>
                    </Grid.RenderTransform>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            ...
                            <VisualState x:Name="Indeterminate">
                                <Storyboard RepeatBehavior="Forever">
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="Animation">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="0.25"/>
                                        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.25"/>
                                        <EasingDoubleKeyFrame KeyTime="0:0:2" Value="0.25"/>
                                    </DoubleAnimationUsingKeyFrames>
                                    <PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)" Storyboard.TargetName="Animation">
                                        <EasingPointKeyFrame KeyTime="0" Value="-0.5,0.5"/>
                                        <EasingPointKeyFrame KeyTime="0:0:1" Value="0.5,0.5"/>
                                        <EasingPointKeyFrame KeyTime="0:0:2" Value="1.5,0.5"/>
                                    </PointAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    ...
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="transitions:TransitionAssist.DisableTransitions" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource OnLoadedNoAnimation}" Name="BeginStoryboardOnLoadedNoAnimation" />
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <RemoveStoryboard BeginStoryboardName="BeginStoryboardOnLoadedNoAnimation" />
                        </Trigger.ExitActions>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsVisible" Value="True" />
                            <Condition Property="transitions:TransitionAssist.DisableTransitions" Value="False" />
                ...
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Full code https://github.com/ButchersBoy/MaterialDesignInXamlToolkit/blob/master/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ProgressBar.xaml

Joe
  • 6,773
  • 2
  • 47
  • 81
  • 1
    "Is there anything I can do to run the storyboard animation in another thread?" Why not run the process in another thread? – 15ee8f99-57ff-4f92-890c-b56153 Jun 26 '16 at 18:05
  • I nearly added that, good point. Is there any way I can load UX components in another thread? Pretty sure its the WPF components loading, rather than me loading data etc – Joe Jun 26 '16 at 20:27
  • @Ed that'd be interesting, I've not heard you can. @ Joe [all](http://stackoverflow.com/questions/3806535/wpf-loading-animation-on-a-separate-ui-thread-c) [these](http://stackoverflow.com/questions/3162010/wpf-animation-stops-when-another-thread-running) [questions](http://stackoverflow.com/questions/14687870/wpf-run-animation-in-a-separate-thread) are very similar to yours - their answers don't help you? **Are you absolutely sure it's not you loading the data?** Because that's the most common mistake - loading data on the UI-thread. Post your loading code and we'll see! – Markus Hütter Jun 27 '16 at 09:36
  • @MarkusHütter I've never bothered trying, myself. This answer says you can: http://stackoverflow.com/a/5818728/424129 Anyway, never say never, but I'd like to see OP's code too. – 15ee8f99-57ff-4f92-890c-b56153 Jun 27 '16 at 11:24
  • @Ed interesting! Though I doubt this is applicable to parts of a single window! – Markus Hütter Jun 27 '16 at 12:00
  • @MarkusHütter Yes, my impression is it's per-window. But you can always slap stuff in a dialog. – 15ee8f99-57ff-4f92-890c-b56153 Jun 27 '16 at 12:04
  • 1
    @MarkusHütter Right on cue, [here's an example](http://stackoverflow.com/a/38054336/424129). – 15ee8f99-57ff-4f92-890c-b56153 Jun 27 '16 at 12:53
  • I'll perform all the data loading in the background (I need to do it anyway) before taking a further look at the WPF loading side of things. But going between these two screens doesn't include any loading (from disk or database) as those objects are loaded just prior to it. I can step through the constructor where it sets the data in the observable collection etc, and it takes ms. Not sure how I'd share the code, as it's such a big project, and it being performance related, it's hard to distill down into a small example project. – Joe Jun 27 '16 at 13:15
  • Then you need to do some debugging. VS2015 has some nice diagnostics tools. Look for what happens during that hang time. It might be Bindings, it might be ValueConverters that are messing things up for you. – Markus Hütter Jun 27 '16 at 13:34
  • I did a while back and I seem to remember the bottleneck may have been the MVVM framework's view-model bindings using reflection (Caliburn). So my options were, deal with a 3s delay and shove a spinner in there, or completely change the MVVM framework. But I'd have to do some more debugging to confirm. – Joe Jun 27 '16 at 13:48

0 Answers0