Как я могу избежать мерцания в полноэкранном приложении WPF?

У меня есть приложение WPF, которое является полноэкранным приложением киоска. Это - на самом деле довольно сложное приложение в этой точке, но здесь является некоторым кодом, который показывает основную идею. По существу, каждый раз, когда пользователь идет от одного экрана до следующего, существует некоторое серьезное продолжение мерцания, поднимающее новое окно. В серьезных случаях рабочий стол отображен в течение нескольких секунд, прежде чем новый экран обнаружится. Этого не происходит в этом примере кода, потому что это настолько просто, но добавьте еще несколько кнопок и стилей, и Вы будете видеть его.

App.xaml.cs:

public partial class App : Application {
    Manager mManager;
    public App() {
        mManager = new Manager();
        Window1 screen1 = new Window1(mManager);
        mManager.Screen1 = screen1;
        try {
            this.Run(screen1);
        } catch (Exception e) {
            System.Console.WriteLine(e.ToString());                
        } finally {
            Application.Current.Shutdown();
        }
    }
}

Window1.xaml.cs:

public partial class Window1 : Window {
    Manager Manager{get; set;}
    public Window1(Manager inManager) {
        InitializeComponent();
        Manager = inManager;
    }

    private void OnChangeScreen(object sender, RoutedEventArgs e) {
        Manager.OpenScreen2();
    }
}

Window2.xaml.cs:

public partial class Window2 : Window {
    Manager Manager{get; set;}
    public Window2(Manager inManager) {
        InitializeComponent();
        Manager = inManager;
    }

    private void OnChangeScreen(object sender, RoutedEventArgs e) {
        Manager.OpenScreen1();
    }
}

Manager.cs:

public class Manager {
    public Window1 Screen1{ get; set;}
    public Window2 Screen2{ get; set;}

    public Manager(){
        Screen1 = new Window1(this);
    }

    public void OpenScreen2() {
        Screen2 = new Window2(this);
        Screen2.Show();
        if (Screen1 != null) {
            Screen1.Hide();
        }
    }

    public void OpenScreen1() {
        Screen1 = new Window1(this);
        Screen1.Show();
        if (Screen2 != null) {
            Screen2.Hide();
        }
    }
}

Window1.xaml (по существу подражавший window2.xaml):

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" 
        WindowStyle="None"
        WindowState="Maximized"
        Width="1280"
        Height="1024"
        FontFamily="Global User Interface"
        ResizeMode="NoResize">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Button Name="ChangeScreenButton" Click="OnChangeScreen" Grid.Row="2" Grid.Column="2" Content="Toggle Screen 2"></Button>
    </Grid>
</Window>

Чередование дисплеев этих двух окон (т.е., показ окна 1 прежде, чем удалить окно 2, и т.д.) не изменяют мерцающее поведение. В этом простом приложении было бы возможно просто скрыть другие экраны, которые не показывают, но в более сложном приложении, существует только слишком много информации состояния для управления информацией об экране правильно и легко.

Есть ли некоторая волшебная кодовая комбинация или техника для предотвращения мерцания, которое работало бы в этом простом приложении, которое также масштабируется к более сложному приложению? Я волнуюсь, что буду вынужден переписать весь UI в этой точке для поддержки сокрытия и показа, и это просто не выполнимо в мой период времени.

Править: Я попробовал скрыться/показать вещь на некоторых диалоговых окнах, и это просто, кажется, не имеет значения. Возможно, это - потому что основное приложение киоска является тяжелым стилем?

11
задан mmr 2 March 2010 в 15:37
поделиться

6 ответов

Основная причина мерцания заключается в том, что всякий раз, когда вы .Hide() окна, его PresentationSource отключается, вызывая Unloaded события для всего и все кэшированное в MILCore слое WPF отбрасывается. Затем, когда вы .Show() снова покажете его позже, все будет восстановлено.

Чтобы предотвратить мерцание, убедитесь, что ваш пользовательский интерфейс постоянно подключен к PresentationSource. Это можно сделать несколькими способами:

Одно окно с замаскированным TabControl

Используйте одно окно, содержащее TabControl, стилизованный так, чтобы не было видно вкладок. Переключайте вкладки в коде, когда вы обычно показываете или скрываете окна. Вы можете просто найти и заменить "Window" в существующем коде на "Page", затем заменить вызовы "Show()" на свой собственный "Show()", который делает следующее:

  1. Проверьте наличие ранее созданного TabItem для этой страницы (используя словарь)
  2. Если TabItem не найден, оберните страницу в новый TabItem и добавьте его в TabControl
  3. Переключите TabControl на новый TabItem

ContentTemplate, который вы будете использовать для вашего TabControl, очень прост:

<ContentTemplate TargetType="TabControl">
  <ContentPresenter x:Name="PART_SelectedContentHost"
                    ContentSource="SelectedContent" />
</ContentTemplate>

Использование фрейма с навигацией

Использование Frame с навигацией - очень хорошее решение для киоска, поскольку оно реализует большую часть переключения страниц и других функций. Однако обновление существующего приложения таким образом может оказаться более трудоемким, чем использование TabControl. В любом случае вам нужно преобразовать Window в Page, а с Frame вам также придется иметь дело с навигацией.

Многочисленные окна с непрозрачностью

Вы можете сделать окно почти полностью невидимым, используя низкую непрозрачность, и при этом WPF будет сохранять визуальное дерево. Это было бы тривиальным изменением: Просто замените все вызовы Window.Show() и Window.Hide() на вызовы "MyHide()" и "MyShow()", которые обновляют непрозрачность. Обратите внимание, что вы можете усовершенствовать этот процесс, если эти процедуры будут запускать анимацию очень короткой длительности (например, 0,2 секунды), которая изменяет непрозрачность. Поскольку обе анимации будут запущены одновременно, анимация будет происходить плавно, и это будет красивый эффект.

15
ответ дан 3 December 2019 в 06:46
поделиться

Мне любопытно, почему вы используете несколько окон для одного и того же приложения в киоске. Вы можете легко поместить все элементы управления в одно и то же «Окно» и просто изменить видимость на панелях для отображения разных «экранов».Это определенно предотвратит отображение рабочего стола и позволит вам делать такие изящные вещи, как плавные переходы, скользящие анимации и т. Д.

2
ответ дан 3 December 2019 в 06:46
поделиться

WPF имеет встроенную навигационную функциональность.

Просто посмотрите на классы Frame и Page, которые вы можете легко спроектировать с помощью VS или Blend.

1
ответ дан 3 December 2019 в 06:46
поделиться

Согласен с комментариями об использовании встроенных функций навигации, но если вы заблокированы дизайн на этом этапе, возможно, подумайте об анимации непрозрачности ваших окон? Короткая 100 или 200 мс анимация непрозрачности от 1 до 0 для исходящего окна и 0 -> 1 для входящего окна может решить проблему. Обработайте фактическую очистку исходящего окна в событии Completed на раскадровке.

0
ответ дан 3 December 2019 в 06:46
поделиться

Поскольку WPF использует DirectX и графический процессор для разгрузки обработки элементов экрана, обновлены ли DirectX и драйверы компьютера?

Cory

0
ответ дан 3 December 2019 в 06:46
поделиться

Если у вас есть какая-либо инициализация в конструкторе, которая занимает много времени, это может вызвать задержку и мерцание. Можно попробовать использовать асинхронный метод или поместить эту инициализацию в фоновый поток, чтобы она не блокировала показ окна.

Примером того, что может вызвать задержку, может быть запрос к базе данных или запрос данных по сети.

Быстрым экспериментом может быть отключение части конструктора в медленном окне, чтобы выяснить, что вызывает задержку показа окна.

0
ответ дан 3 December 2019 в 06:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: