2010-03-02 3 views
11

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

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

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

ответ

15

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

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

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

+0

Спасибо за объяснение. – mmr

2

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

+0

Это очень и очень интересная идея. Я не уверен, сколько времени потребуется, чтобы переключиться на этот подход (опять же, проблемы состояния, это было приложение WinForms, переведенное в WPF), но это может стоить эксперимента или двух. – mmr

+5

Другая идея, которая может помешать этому ... Если долгое время отображать последующие окна, это может быть связано с тем, что компьютер увяз, попробовав сделать все. Вы можете «показать» все окна при запуске и переключаться между ними, активируя нужное окно. Таким образом, это просто окна, переключающие активное (сверху) окно, а не фактическое отображение всех компонентов на каждом переходе. – NebuSoft

1

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

Просто посмотрите на классы Frame и классы, которые вы можете легко проектировать, используя VS или Blend.

+0

и NavigationWindow. – Will

0

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

+0

Утонченная идея, но мне сказали, что мне не разрешено быть творческим с чем-то подобным, просто чтобы сделать вещи быстрее. – mmr

+0

Если ваша проблема связана с разделом разработчиков/разработчиков, вы можете создать раскадровку в коде, чтобы избежать проблем с существующими анимациями. Если это всего лишь проблема политики, ну ... Думаю, им нравится их мерцание. :) –

+0

«Это похоже на искусство для меня! Ты кодер, тебе не разрешено быть художником! Это не то, за что мы платим тебе! Вернись на мины!» своего рода менталитет. – mmr

0

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

Cory

+0

Это происходит на каждой машине, на которой тестируется приложение, и все они должны быть полностью обновлены. Если .NET потребует установки большего количества драйверов directx, я думаю, что это будет часть установки ... но у моей машины Dev, конечно же, установлен самый последний DirectX, и он мерцает здесь. – mmr

0

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

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

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

0

Как ответил ранее с помощью Frames/Tab Controls избежать мерцания во время переходов

Если вы не хотите, чтобы изменить свое приложение и хотите удалить, что мерцание (мигание рабочего стола между ними) на Windows7 или WindowsVista вы можете оптимизировать ваши окна «Визуальные эффекты» устанавливаются как 'Adjust for best performance'

+1

На самом деле это не общее решение - мы не можем просить всех наших клиентов отключить темы рабочего стола из-за нашей неспособности кодирования. Нам просто нужно поправляться. – mmr

0

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

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

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

В LanguageWindow.xaml.vb:

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)

Смежные вопросы