2010-03-02 83 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> 

交错的两个窗口的显示(即,示出删除窗口2等前窗1)不改变闪烁行为。在这个简单的应用程序中,可以隐藏未显示的其他屏幕,但在更复杂的应用程序中,只有太多的状态信息才能正确,轻松地管理屏幕信息。

是否有一些神奇的代码字或技术,以避免闪烁,将在这个简单的应用程序,也扩展到更复杂的应用程序工作?我担心在这一点上我将被迫重写整个用户界面以支持隐藏和显示,这在我的时间范围内是不可行的。

编辑:我试过隐藏/显示的东西在一些对话框上,它似乎并不重要。也许这是因为主亭应用风格沉重?

回答

15

闪烁的根本原因是,每当你.Hide()其PresentationSource断开,造成Unloaded事件窗口中的一切,一切都在MILCore层WPF的缓存被炒到被丢弃。然后当你再次.Show()时,一切都被重建。

为防止闪烁,请确保始终将您的UI连接到PresentationSource。这可以通过几种方式来完成:

与变相的TabControl

使用单一窗口包含TabControl风格,所以你看不到标签的单个窗口。当您正常显示或隐藏窗口时,切换代码中的选项卡。你可以简单地搜索和替换在“页面”现有代码“窗口”,然后将“展()”调用自定义“显示()”,它具有以下功能:

  1. 检查之前创建的TabItem此页面(使用词典)
  2. 如果没有发现的TabItem,包裹页的新的TabItem内,它的TabControl添加到TabControl
  3. 切换到新的TabItem

的的ContentTemplate你将用于你的TabControl是非常简单的:

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

使用带有导航

一个Frame使用Frame与导航是一个小亭一个很好的解决方案,因为它实现了很多的页面切换等功能。然而,用这种方法更新现有的应用程序可能比使用TabControl更有用。无论哪种情况,您都需要将Window转换为Page,但使用Frame还需要处理导航。

与透明度

多个窗口可以使窗口几乎完全看不到使用低透明度,但WPF仍然将保持视觉树周围。这将是一个微不足道的变化:只需更换所有调用Window.Show()Window.Hide()与调用“MyHide()”和“MyShow()”更新不透明度。请注意,您可以通过让这些例程触发非常短的动画(例如0.2秒)使不透明度动画,从而进一步改善这一点。由于这两个动画将在同一时间设置动画将顺利进行,这将是一个整洁的效果。

+0

感谢您的解释。 – mmr 2010-03-02 17:03:11

2

我很好奇你为什么在一个自助服务终端中为同一个应用程序使用多个窗口。您可以轻松将所有控件放在同一个“窗口”中,只需更改面板上的可见性即可显示不同的“屏幕”。这肯定会阻止桌面被显示出来,并且可以让你做像淡入淡出的过渡或滑动动画等整洁的东西。

+0

这是一个非常非常有趣的想法。我不知道需要多长时间才能切换到这种方法(再次,状态问题;这曾经是一个WinForms应用程序切换到WPF),但它可能是值得一两个实验。 – mmr 2010-03-02 15:48:08

+5

另一个可能阻止这种情况的想法...如果显示后续窗口花费很长时间,可能是因为计算机正在尝试渲染所有内容。您可能想要在启动时“显示”所有窗口,并通过激活您想要的窗口在它们之间切换。这样,它只是窗口切换活动(在顶部)窗口,而不必实际渲染每个转换中的所有组件。 – NebuSoft 2010-03-02 15:59:36

1

WPF内置了导航功能。

请看Frame和你可以使用VS或Blend轻松设计的Page类。

+0

和NavigationWindow。 – Will 2010-03-02 15:49:51

0

同意有关使用内置导航功能的注释,但如果此时您已锁定到您的设计中,那么可能考虑将视窗的不透明度设置为动画效果?一个简短的100或200毫秒不透明度动画从1 - > 0为传出窗口和0 - > 1为传入窗口可能会解决此问题。在故事板上的Completed事件中处理传出窗口的实际清理。

+0

整洁的想法,但我被告知我不允许对这样的事情有创意,只是为了让事情变得更快。 – mmr 2010-03-02 16:05:07

+0

如果您担心整个设计师/开发者分离,则可以使用代码创建故事板以避免现有动画出现问题。如果这只是一个政策问题,那么......我想他们喜欢他们的闪烁。 :) – 2010-03-02 16:30:12

+0

它更像是一个“对我来说看起来像艺术!你是一名编码员,你不允许成为一名艺术家!这不是我们付出的代价!回到矿山!”有种心态。 – mmr 2010-03-02 17:02:26

0

看到WPF如何使用DirectX和图形处理器卸载屏幕元素的处理,计算机的DirectX和驱动程序是否是最新的?

科里斯

+0

这发生在应用程序测试的每台机器上,并且它们都应该完全更新。如果.NET需要安装更多的directx驱动程序,我认为它会成为安装程序的一部分......但我的开发机器当然安装了最新的directx,并且在这里闪烁。 – mmr 2010-03-02 16:18:45

0

如果你有在需要很长的时间,可能会导致延迟和闪烁的构造函数的初始化。您可以尝试使用异步方法,或将该初始化放在后台线程上,以免它阻止显示窗口。

一个会导致延迟的例子是数据库查询或通过网络对数据的请求。

一个快速的实验是在缓慢的窗口中禁用构造函数的一部分,以找出导致窗口显示延迟的原因。

0

正如前面使用框架回答/标签控件避免转换过程闪烁

如果你不想改变你的应用程序,并希望删除闪烁(在桌面之间的闪烁),Windows7的上或WindowsVista的可以优化你的窗户'视觉效果'设置为'Adjust for best performance'

+1

这不是一个真正的通用解决方案 - 我们不能要求我们所有的客户都关闭桌面主题,因为我们的编码不可行。我们必须变得更好。 – mmr 2011-06-19 01:45:31

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完成)