I have a usercontrol with some buttons, textblocks and a ContentControl that will load other (3) different usercontrols within the same usercontrol. The buttons from the parent usercontrol will stay so I can keep iterating through the other (3) usercontrols. Those (3) usercontrols contain 1, 2, or 3 DataGrids with several row, and this may take a second or two to load (at least while debugging). I want to display an animation to indicate this. However, I cannot load those user controls async in order to display the animation, which waits until the usercontrol is loaded.
I don't see why my code wouldn't work. The parent usercontrol looks like this:
And when I click one of the three buttons at the bottom, a different usercontrol loads within the parent usercontrol, using the ContentControl.
The parent user control is something like this:
<UserControl>
<DockPanel LastChildFill="True">
<Grid DockPanel.Dock="Top" >
<Control Visibility="{Binding LoadingVisilibity}" Style="{StaticResource BusyAnimationStyle}" Panel.ZIndex="10"/>
<ContentControl Content="{Binding ContentPanel}"></ContentControl>
</Grid>
</DockPanel>
</UserControl>
The BusyAnimationStyle just displays circles turning around.
<Style x:Key="BusyAnimationStyle" TargetType="{x:Type Control}">
<Setter Property="Background" Value="#9F000000"/>
<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:0.8" Value="{StaticResource UnfilledColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Animation1" BeginTime="00:00:00.1" 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:00.8" Value="{StaticResource UnfilledColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Animation2" BeginTime="00:00:00.2" 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:00.8" Value="{StaticResource UnfilledColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Animation3" BeginTime="00:00:00.3" 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:00.8" Value="{StaticResource UnfilledColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Animation4" BeginTime="00:00:00.4" 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:00.8" Value="{StaticResource UnfilledColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Animation5" BeginTime="00:00:00.5" 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:00.8" Value="{StaticResource UnfilledColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Animation6" BeginTime="00:00:00.6" 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:00.8" Value="{StaticResource UnfilledColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Animation7" BeginTime="00:00:00.7" 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:00.8" 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>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
private Visibility loadingVisilibity;
public Visibility LoadingVisilibity
{
get => loadingVisilibity;
set
{
loadingVisilibity = value;
OnPropertyChanged(nameof(LoadingVisilibity));
}
}
To change the Content of the ContentControl, I have three buttons each like:
private ICommand firstBtnCommand;
public ICommand FirstViewBtnCommand
{
get
{
return firstBtnCommand ?? (firstBtnCommand = new CommandHandler((param) => ChangeView("first"), true));
}
}
And the function:
private async void ChangeView(string view)
{
LoadingVisilibity = Visibility.Visible;
await Application.Current.Dispatcher.InvokeAsync(()=>
{
if (view == "first") { ContentPanel.Content = this.firstViewModel; }
else if (view == "second") { ContentPanel.Content = this.secondViewModel; }
else { ContentPanel.Content = this.thirdViewModel; }
});
LoadingVisilibity = Visibility.Collapsed;
}
I also tried:
await Application.Current.Dispatcher.BeginInvoke(
new ThreadStart(() =>
{
if (view == "first") { ContentPanel.Content = this.firstViewModel; }
else if (view == "second") { ContentPanel.Content = this.secondViewModel; }
else { ContentPanel.Content = this.thirdViewModel; }
}));
However, the animation doesn't happen. Sometimes I can see a bit just after the elements are loaded, but not while the ContentControl is loading.
I have done this before and usually goes like:
await Task.Run(() =>
{
if (view == "first") { ContentPanel.Content = this.firstViewModel; }
else if (view == "second") { ContentPanel.Content = this.secondViewModel; }
else { ContentPanel.Content = this.thirdViewModel; }
});
However, in this case tells me
The calling thread cannot access this object because a different thread owns it
I am lost now after trying so many different things, and I don't see anything wrong with my code.
How can I load the animation while the ContentControl content is loading? Is there a better way of doing this? Surely this looks like the right approach.
Let me know if there is more information that I can provide.