Как отобразить значок загрузки во время навигации по фрейму? - PullRequest
1 голос
/ 16 июня 2009

У меня есть приложение WPF с рамкой и TreeView. TreeView отображает меню для моего приложения, и при щелчке по элементу Frame отображает содержимое этого пункта меню посредством вызова Navigate. Этот вызов иногда занимает несколько секунд, и пользовательский интерфейс блокируется, когда навигация завершается.

У меня есть элемент управления с анимированными вращающимися кругами (я называю это WaitIcon), который я хотел бы отобразить во время загрузки кадра, но он не появляется (и не будет вращаться, даже если он появился), потому что поток пользовательского интерфейса заблокирована загрузка содержимого фрейма. Я не могу вызвать Navigate в фоновом потоке, потому что фрейм принадлежит потоку пользовательского интерфейса. Есть ли способ показать WaitIcon во время загрузки кадра? Возможно, создав второй поток, которому принадлежит WaitIcon?

ОБНОВЛЕНИЕ - Пример кода, показывающий проблему ниже:

Вот главное окно. Я только что использовал анимированный Ellipse для имитации 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>

Событие нажатия кнопки:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Ellipse1.Visibility = Visibility.Visible;
    ContentFrame.Source = new Uri("TestPage.xaml", UriKind.Relative);
}

Тестовая страница:

<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>

И я засыпал в конструкторе для имитации длительной инициализации:

public partial class TestPage : Page
{
    public TestPage()
    {
        InitializeComponent();
        Thread.Sleep(3000);
    }
}

Эллипс отображается только после загрузки страницы.

1 Ответ

0 голосов
/ 16 июня 2009

Анимация WPF при запуске не может быть заблокирована основным потоком. Раскадровка выполняется в своем собственном потоке, а рендеринг происходит в потоке рендеринга WPF, который отличается от основного. Кроме того, я считаю, что загрузка кадра также неблокирует.

Так что с вашим кодом происходит что-то еще, почему бы вам не опубликовать его здесь, чтобы мы могли понять.

РЕДАКТИРОВАТЬ: я был неправ насчет раскадровки. Поскольку ресурс создается в основном потоке, он работает в том же основном потоке. И даже если вы создадите раскадровку динамически, она не сможет анимировать объекты из окон, созданных в главном потоке.

И я ошибся насчет фрейма - он блокирует основной поток при загрузке URL. Я всегда использовал элемент управления WebBrowser, который не блокирует.

Итак, у вас есть два варианта (возможно, больше, но я перечислю два):

  • Создайте окна с анимацией в другом потоке, как описано здесь .
  • Использовать веб-браузер вместо фрейма.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...