Как избежать мерцания в полноэкранном приложении 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();
    }
}

диспетчер.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 и т. д.) не изменяет поведение мерцания. В этом простом приложении можно было бы просто скрыть другое экраны, которые не отображаются, но в более сложном приложении, есть слишком много информации о состоянии для управления информацией экрана правильно и легко.

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

EDIT: я пробовал Скрыть / показать вещь в некоторых диалогах, и это просто не имеет значения. Может быть, это потому, что основной киоск приложение стиль тяжелый?

8 ответов


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

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

одно окно с замаскированный элемент управления TabControl

используйте одно окно, содержащее TabControl стиль, чтобы вы не могли видеть вкладки. Переключайте вкладки в коде, когда вы обычно показываете или скрываете окна. Вы можете просто найти и заменить "окно" в существующем коде на "страницу", а затем заменить вызовы" 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 with Navigation-очень хорошее решение для киоска, потому что оно реализует множество функций переключения страниц и других функций. Однако может быть больше работы для обновления существующее приложение таким образом, чем использовать TabControl. В любом случае вам нужно преобразовать из Window to Page, но с Frame вам также нужно иметь дело с навигацией.

несколько окон с прозрачностью

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


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


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

просто посмотри рама и классы страниц, которые вы можете легко создать с помощью VS или Blend.


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


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

Кори


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

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

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


Как ответили ранее, используя элементы управления Frames / Tab, избегайте мерцания во время переходов

Если вы не хотите менять свое приложение и хотите удалить это мерцание (мигание рабочего стола между ними) на Windows7 или WindowsVista, вы можете оптимизировать настройку "визуальные эффекты" для windows 'настройка для лучшей производительности'


вот простая альтернатива, которая работает для меня в моем киоске-как приложение с черным фоном, вдохновленный сверху ответы. Здесь у меня есть" LanguageWindow", который можно открыть из любой точки приложения, чтобы изменить текущий язык.

В LanguageWindow.xaml (проверьте WindowState=свернуто):

<Window x:Class="LanguageWindow"
    ...
    Title="LanguageWindow" Height="1024" Width="1280" WindowStyle="None" WindowState="Minimized" Background="Black">

В LanguageWindow.код XAML.В. Б.:

Private Sub LanguageWindow_ContentRendered(sender As Object, e As EventArgs) Handles Me.ContentRendered
    Me.WindowState = WindowState.Maximized
End Sub

вуаля!

(сделано с Visual Studio 2015, .NET Framework 4.6, WPF, VB.net)