I have a WPF application with a Frame and a TreeView. The TreeView displays the menu for my application, and when an item is clicked, the Frame displays the content for that menu item via a call to Navigate
. That call sometimes takes several seconds, and UI is blocked while navigation completes.
I have a control with animated spinning circles (I call it a WaitIcon) that I would like to display while the frame loads, but it doesn't appear (and would not spin even if it did appear) because the UI thread is blocked loading the Frame's content. I can't call Navigate
on a background thread because the frame is owned by the UI thread. Is there a way to show the WaitIcon while the frame loads? Possibly by creating a second thread that owns the WaitIcon?
UPDATE -- Sample code showing the problem below:
Here is the main window. I've just used an animated Ellipse to simulate the WaitIcon:
<Window x:Class="FrameLoadingTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Storyboard x:Key="Animation" RepeatBehavior="Forever">
<ColorAnimation From="Red" To="Black" Duration="0:0:2" Storyboard.TargetName="Ellipse1" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" />
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource Animation}" />
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="5*" />
</Grid.ColumnDefinitions>
<Button Click="Button_Click">Load Frame</Button>
<Frame Name="ContentFrame" Grid.Column="1"></Frame>
<Ellipse Name="Ellipse1" Height="100" Width="100" Visibility="Hidden" Fill="Red">
</Ellipse>
</Grid>
</Window>
The click event for the button:
private void Button_Click(object sender, RoutedEventArgs e)
{
Ellipse1.Visibility = Visibility.Visible;
ContentFrame.Source = new Uri("TestPage.xaml", UriKind.Relative);
}
The test page:
<Page x:Class="FrameLoadingTest.TestPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestPage">
<Grid>
<TextBlock>Hello, world</TextBlock>
</Grid>
</Page>
And I put a sleep in the constructor to simulate a long running initialization:
public partial class TestPage : Page
{
public TestPage()
{
InitializeComponent();
Thread.Sleep(3000);
}
}
The ellipse does not show up until after the page loads.