上一章介绍了有关WPF应用程序中使用Application对象的方式,接下来看一下如何使用Application对象来处理一些更普通的情况,接下俩介绍如何初始化界面、如何处理命名行参数、如何处理支付窗口之间的交互、如何添加跟踪文档以及如何创建单示例应用程序。

一、显示初始化界面

  WPF应用程序的运行速度快,但并不能在瞬间启动。当第一次启动应用程序时,会有一些延迟,因为公共语言运行时(Common Language Runtime,CLR)首先需要初始化.NET环境,然后启动应用程序。

  这一延迟未必成为问题。通常,只需要经历很短的时间,就会出现第一个窗口,但如果具有更耗时的初始化步骤,或者如果只是希望通过显示打开的图像应用程序显得更加专业,这时可使用WPF提供的简单初始界面特性。

  下面是添加初始界面的方法:

  (1)为项目添加图像文件(通常是.bmp、.png或.jpg文件)。

  (2)在Solution Explorer中选择图像文件。

  (3)将Build Action修改为SplashScreen。

  下次运行应用程序时,图像会立即在屏幕中央显示出来。一旦准备好运行时环境。而且Application_Startup方法执行完毕,应用程序的第一个窗口就将显示出来,这时初始化界面图像会很快消失(约需300毫秒).

  该特性听起来很简单,事实上也确实如此。只需要记住显示的初始化界面没有任何装饰,在它周围没有窗口边框,所有由你决定是否为初始界面图像添加边框,也无法通过显示一系列的多幅图像或动画让初始化图像显得更富有想象力的效果。如果希望得到这种效果,需要采用传统方法:创建在运行初始化代码的同事显示你所希望的图像界面的启动窗口。

  顺便提一下,当添加初始界面时,WPF编译器会自动生成的App.g.cs文件添加与下面的类似的代码:

  1. SplashScreen splashScreen = new SplashScreen("images/blue.jpg");
  2. //Show the splash screen
  3. //The true parameter sets the splashScreen to fade away automatically
  4. //after the first window appears
  5. splashScreen.Show(true);
  6.  
  7. //Start the application
  8. AssemblyResources.App app = new AssemblyResources.App();
  9. app.InitializeComponent();
  10. app.Run();
  11. //The splash screen begins ites automatic fade-out now.

  也可自行编写这一剪短逻辑,而不死使用SplashScreen 生成操作。但有一点需要指出,可以改变的唯一细节是初始界面褪去的速度。为此,需要项SplashScreen.Show()方法传递false(从而使WPF不会自动淡入初始化界面)。然后由你负责通过调用SplashScreen.Close()方法在恰当的时机隐藏初始界面,并提供TimeSpan值来指示经过多长时间淡出初始化界面。

二、处理命令行参数

  为处理命令行参数,需要相应Application.Startup事件。命令行参数是通过StartupEventArgs.Args属性作为字符串数组提供的。

  例如,假定希望加载文档,文档名作为命令行参数传递。在这种情况下,有必要读取命令行参数并执行所需的一些额外初始化操作。在下面的示例中,通过响应Application.Startup事件实现了这一模式。在该例中,没有在任何地方设置Application.StartupUri属性——而是使用代码实例化窗口。

  1. public partial class App : Application
  2. {
  3. // The command-line argument is set through the Visual Studio
  4. // project properties (the Debug tab).
  5. private void App_Startup(object sender, StartupEventArgs e)
  6. {
  7. // At this point, the main window has been created but not shown.
  8. FileViewer win = new FileViewer();
  9.  
  10. if (e.Args.Length > )
  11. {
  12. string file = e.Args[];
  13. if (File.Exists(file))
  14. {
  15. // Configure the main window.
  16. win.LoadFile(file);
  17. }
  18. }
  19.  
  20. // This window will automatically be set as the Application.MainWindow.
  21. win.Show();
  22. }
  23. }
  1. <Application x:Class="LoadFromCommandLine.App"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Startup="App_Startup">
  5. <Application.Resources>
  6.  
  7. </Application.Resources>
  8. </Application>

App.xaml

  上面的方法初始化主窗口,然后当App_Startup()方法结束是显示主窗口。上面的代码假定FileViewer类有名为LoadFile()的共有方法。这只是一个示例,它只读取并显示指定文件的文本。

三、访问当前Application对象

  通过静态的Application.Current属性,可在应用程序的任何位置获取当前应用程序实例,从而在窗口之间进行基本交互,因为任何窗口都可以访问当前Application对象,并通过Application对象,并通过Application对象获取主窗口的作用:

  1. Window main=Application.Current.MainWindow;
  2. MessageBox.Show("The main window is "+main.Title);

  当然,如果希望访问在自定义主窗口类中添加的任意方法、属性或事件,需要将窗口对象转换为正确类型。如果主窗口的自定义类MainWindow的实例,可使用与下面类似的代码:

  1. MainWindow main=(MainWindow)Application.Current.MainWindow;
  2. main.DoSomething();

  在窗口中还可以检查Application.Windows集合的内容,该属性提供了所有当前打开窗口的引用:

  1. foreach(Window window in Application.Current.Windows)
  2. {
  3. MessageBox.Show(window.Title+" is open.");
  4. }

  实际上,大多数应用程序通常使用一种更具结构化特点的方式在窗口之间进行交互。如果有几个长时间运行的窗口同事打开,并且它们之间需要以某种方式进行通信,在自定义应用程序类中保存这些窗口的引用可能更有意义。这样,总可以找到所需的窗口。与此类似,如果有基于文档的应用程序,那么可选择创建跟踪文档窗口的集合,而不是跟踪其他内容。

四、在窗口之间进行交互

  整如在前面已经看到的,自定义应用程序类是放置响应不同应用程序事件的代码的好地方。应用程序类还可以很好地达到另一个目的:保存重要窗口的引用,使一个窗口可访问另一个窗口。

  例如,假设希望跟踪应用程序使用的所有文档窗口。为此,可在自定义应用程序类中创建专门的集合。下面是使用泛型列表集合保存一组自定义窗口对象的示例。在这个示例中,每个文档窗口由名为Document类的实例表示:

  1. public partial class App : Application
  2. {
  3. private List<Document> documents = new List<Document>();
  4.  
  5. public List<Document> Documents
  6. {
  7. get { return documents; }
  8. set { documents = value; }
  9. }
  10. }

  现在,当创建新文档时,只需要记住将其添加到Documents集合中即可。下面是响应按钮单击事件的事件处理程序,该事件处理程序完成了所需的工作:

  1. private void cmdCreate_Click(object sender, RoutedEventArgs e)
  2. {
  3. Document doc = new Document();
  4. doc.Owner = this;
  5. doc.Show();
  6. ((App)Application.Current).Documents.Add(doc);
  7. }

  同样,也可在Document类中响应Window.Loaded类这些事件,以确保当创建文档对象时,总会在Documents集合中注册该文档对象。

  现在,可在代码的其他任何地方进行集合来遍历所有文档,并使用公有成员。在该例中,Document类包含用于更新显示的自定义方法SetContent();

  1. private void cmdUpdate_Click(object sender, RoutedEventArgs e)
  2. {
  3. foreach (Document doc in ((App)Application.Current).Documents)
  4. {
  5. doc.SetContent("Refreshed at " + DateTime.Now.ToLongTimeString() + ".");
  6. }
  7. }
  1. <Window x:Class="WindowTracker.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="WindowTracker" Height="300" Width="300"
  5. >
  6. <StackPanel>
  7. <Button Click="cmdCreate_Click" Margin="10,10,10,5" Name="cmdCreate">Click to Create a Document</Button>
  8. <Button Click="cmdUpdate_Click" Margin="10,5,10,10" Name="cmdUpdate">Click to Refresh the Documents</Button>
  9. </StackPanel>
  10. </Window>

MainWindow.xaml

  1. <Window x:Class="WindowTracker.Document"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="WindowTracker" Height="78" Width="209"
  5. >
  6. A new document.
  7. </Window>

Document.xaml

  1. public partial class Document : Window
  2. {
  3. public Document()
  4. {
  5. InitializeComponent();
  6. }
  7.  
  8. public void SetContent(string content)
  9. {
  10. this.Content = content;
  11. }
  12. }

Document.xaml.cs

  下图显示了最终效果图。最终结果谈不上华美,但这种交互方式值得注意——演示了一种通过自定义应用程序类在窗口之间进行交互的安全规范的方式。这种方式比使用Window属性要好,因为是强类型,只包含Document窗口(而不是包含窗口应用程序中所有窗口的集合)。通过这种方式还可使用另一种更有用的方式对窗口进行分类。例如,可使用字典集合,通过键名更方便地查找文档。在基于文档的引用程序中,可通过文件名来索引集合中的窗口。

五、单实例应用程序

  通常,只要愿意就可以加载WPF应用程序的任意多个副本。某些情况下, 这种设计时非常合理的。但在另外一些情况下,这可能会成为问题,当构建基于文档的应用程序时更是如此。

  对于单实例应用程序,WPF本身并未提供自带的解决方法,但可使用几种变通方法。基本技术时当触发Application.Startup事件时,检查另一应用程序实例是否已在运行。最简单的方法是使用全局的mutex对象(mutex对象时操作系统提供的用于进程间通信的同步对象)。这种方法很简单,但功能有限。最重要的是,应用程序的新实例无法与已经存在的实例进行通信。对于基于文档的应用程序而言这确实是一个问题,因为新实例可能需要告诉已经存在的应用程序实例打开某个特定的文档(如果该文档是通过命令行参数传递的)。

【WPF学习】第二十七章 Application类的任务的更多相关文章

  1. 《Linux命令行与shell脚本编程大全》 第二十七章 学习笔记

    第二十七章:shell脚本编程进阶 监测系统统计数据 系统快照报告 1.运行时间 uptime命令会提供以下基本信息: 当前时间 系统运行的天数,小时数,分钟数 当前登录到系统的用户数 1分钟,5分钟 ...

  2. Gradle 1.12用户指南翻译——第二十七章. Ear 插件

    其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...

  3. “全栈2019”Java多线程第二十七章:Lock获取lock/释放unlock锁

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  4. “全栈2019”Java第八十七章:类中嵌套接口的应用场景(拔高题)

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. “全栈2019”Java第三十七章:类与字段

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. “全栈2019”Java第二十七章:流程控制语句中循环语句for

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  7. 风炫安全WEB安全学习第二十七节课 XSS的防御措施

    风炫安全WEB安全学习第二十七节课 XSS的防御措施 XSS防御措施 总的原则 控制好输入/输出 过滤:根据业务需求进行过滤,对email,手机号码这样的输入框进行验证. 转义:所有输出到前端的数据都 ...

  8. 【WPF学习】第二十六章 Application类——应用程序的生命周期

    在WPF中,应用程序会经历简单的生命周期.在应用程序启动后,将立即创建应用程序对象,在应用程序运行时触发各种应用程序事件,你可以选择监视其中的某些事件.最后,当释放应用程序对象时,应用程序将结束. 一 ...

  9. Java基础知识二次学习--第六章 常用类

    第六章 常用类   时间:2017年4月26日16:14:49~2017年4月26日16:56:02 章节:06章_01节~06章_06节 视频长度:20:57+1:15+8:44+1:26+11:2 ...

随机推荐

  1. 第三阶段:3.Web端产品设计:1.以用户为中心的产品设计2

    从功能到体验.提供不同的附加值.

  2. Java 8 访问接口的默认方法

    Java 8 API提供了很多全新的函数式接口来让工作更加方便,有一些接口是来自Google Guava库里的,即便你对这些很熟悉了,还是有必要看看这些是如何扩展到lambda上使用的. 一.Opti ...

  3. Omnigraffle 许可证

    名字:Appked 序列号:MFWG-GHEB-HYTW-CGHT-CSXU-QCNC-SXU

  4. 0014 标签显示模式:display(重点)

    目标: 理解 标签的三种显示模式 三种显示模式的特点以及区别 理解三种显示模式的相互转化 应用 实现三种显示模式的相互转化 2.1 什么是标签显示模式 什么是标签的显示模式? 标签以什么方式进行显示, ...

  5. mysql主从之双主配置

    mysql双主配置 mysql双主其实就是互相同步,互为主从 任意一台都能够执行插入动作 生产环境用得非常少,因为还是担心数据一致的问题 生产环境一般来说主从已经够用 172.19.132.121的配 ...

  6. 急速搭建 Serverless AI 应用:为你写诗

    前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算 ...

  7. [工具] Git版本管理(二)(分支)

    一.分支 1.git中如何保存版本 在我们以往使用文件来进行版本控制的时候,都是将上一个版本复制一份,然后在其基础上进行修改. 但在git中,git只保存当前版本和上一个版本之间的差异,这样可以节省存 ...

  8. 大数据框架开发基础之Zookeeper入门

    Zookeeper是Hadoop分布式调度服务,用来构建分布式应用系统.构建一个分布式应用是一个很复杂的事情,主要的原因是我们需要合理有效的处理分布式集群中的部分失败的问题.例如,集群中的节点在相互通 ...

  9. .net core 开车记:Data Protection Key 过期问题与登录页面访问慢

    K8s 船还没修好,.net core 车又出了问题,开着 k8s 豪华邮轮.飚着 .net core 极品飞车的好事真是多磨. 自从我们用上 .net core ,就一直被 .net core 的一 ...

  10. java线程相关基本方法

    java线程中常用的基本方法有wait,notify,notifyAll,sleep,join,yield等. 线程的生命周期一共分为五个部分,分别是:新建(New).就绪(Runnable).运行( ...