六,WPF的Application类

  1. Application.ShutdownMode属性:通过,只要有一个窗口还没有关闭,Application类就保持应用程序处于有效状态,如果这不是所期望的行为,就可以调整该属性。QQ图片20140730232135
  2. 应用程序事件
    Application提供了为数不多的几个非常有用的事件,如下图所示:
    QQ图片20140730234316
    有两种选择用于处理事件:在XAML中使用事件特性的方式关联事件处理程序,或重写相应的受保护方法,当重写应用程序方法时,推荐首先调用基类的实现,通常,基类的实现只是引发相应的应用程序事件。
  3. 初始界面(SplashScreen
    WPF应用程序的运行速度快,但不可能在瞬间启动。当第一次启动应用程序时,会有一些延迟,因为公共语言运行时首先需要初始化.Net环境,然后启动应用程序。这一延迟不见得会成为问题,通常,只需要经过很短的时间,就会出现第一个窗口。但是,如果具有更加耗时的初始化步骤,或者如果只是希望通过显示一个打开的图形使应用程序显得更加专业,此时,就可以使用WPF提供的简单的初始界面特性。下面是添加初始界面的方法:
    1)  为项目添加一个图像文件。
    2)  把此图像文件的生成操作设置为SplashScreen
    下次运行应用程序时,该图形会立即在屏幕中央显示出来,一旦准备好了运行时环境,并且Application_Startup方法执行完毕,应用程序的第一个窗口显示出来,这时初始界面图形会很快的逐渐消失(大约300毫米).
    我们可以自己编写初始界面的显示逻辑来改变初始界面褪去的速度,为此,需要向SplashScreen.Show()方法传递false,然后通过调用SplashScreen.Close()方法且可以提供一个TimeSpan值指示经过多长时间淡出初始界面。
  4. 处理命令行参数
    为了处理命令行参数,需要响应Application.Startup事件,命令行参数是通过StartupEventArgs.Args属性作为字符串数组提供的。例如,假定希望加载一个文档,文档的名称作为命令行参数传递,在这种情况下,就有必要读取命令行参数并进行所需要的一些额外的初始化操作,在下面的示例中,通过响应Application.Startup事件实现了这一模式,在该示例中没有在任何地方设置Application.StartupUri属性,而是使用代码实例化主窗口。
    public partial class App : Application
    {
        // The command-line argument is set through the Visual Studio
        // project properties (the Debug tab).
        private void App_Startup(object sender, StartupEventArgs e)
        {           
            // At this point, the main window has been created but not shown.
            FileViewer win = new FileViewer();
    
            if (e.Args.Length > 0)
            {
                string file = e.Args[0];
                if (File.Exists(file))
                {
                    // Configure the main window.                    
                    win.LoadFile(file);
                }
            }
    
            // This window will automatically be set as the Application.MainWindow.
            win.Show();
        }
    }
    View Code

    QQ图片20140731004818

  5. 访问当前Application对象
    通过静态的Application.Current属性,可以在应用程序的任何位置获取当前应用程序实例。
    在一个窗口中可以检查Application.Windows集合的内容,这个集合提供了所有当前打开窗口的引用。
  6. 在窗口这间进行交互
    在应用程序类中我们可以添加代码来保存重要窗口的引用,从而使一个窗口可以访问另一个窗口。例如,假设希望跟踪应用程序使用的所有文档窗口,可以在自定义的应用程序类中创建一个专门的集合。下面是一个使用泛型列表集合保存一组自定义窗口对象的示例。在这个示例中,每个文档窗口由一个名为Document的类的实例表示:
    public partial class App : Application
    {
        private List<Document> documents = new List<Document>();
            
        public List<Document> Documents
        {
            get { return documents; }
            set { documents = value; }
        }
    }
    View Code

    现在,当创建一个新文档时,只需要记住把它添加到Documents集合中即可。下面是响应一个按钮单击事件的事件处理程序,创建一个新文档的同时把它添加到Documents集合中,同样,也可以在Document类中响应Window.Loaded这类事件,以确保当创建文档对象时,总会在Documents集合中注册该文档对象。

    private void cmdCreate_Click(object sender, RoutedEventArgs e)
    {
        Document doc = new Document();
        doc.Owner = this;
        doc.Show();
        ((App)Application.Current).Documents.Add(doc);
    }
    View Code

    现在可以在代码中的其他任何地方使用集合来遍历所有文档,在这个示例中,Document类包含了一个自定义的用于更新显示的SetContent()方法:

    private void cmdUpdate_Click(object sender, RoutedEventArgs e)
    {
        foreach (Document doc in ((App)Application.Current).Documents)
        {
            doc.SetContent("Refreshed at " + DateTime.Now.ToLongTimeString() + ".");
        }            
    }
    View Code
  7. 单实例应用程序
    通常,只要愿意就可以加载WPF应用程序的任意多个副本,在某些情况下,这种设计可能是合理的,但在另一些情况下,这可能是一个问题,比如当创建基于文档的应用程序时。例如,对于Microsoft Word,不管打开多少个文档,一次只能加载一个winword.exe实例,当打开新文档时,它们在新的窗口中显示,但是只有一个应用程序控制所有的文档窗口。
    要创建WPF单实例应用程序,最简单的方法是使用Windows窗体提供的内置支持,这一内置支持最初是用于Visual Basic应用程序的,那么,如何使用为Windows窗体和Visual Basic设计的这一特性来管理C#开发的WPF应用程序呢?本质上,VB应用程序类充当了WPF应用程序的一个包装器,当启动应用程序时,创建VB应用程序类,然后VB应用程序类创建WPF应用程序类,VB应用程序类处理实例管理问题,而WPF应用程序类处理真正的应用程序。
    使用此方法的第一步是添加对Microsoft.VisualBasic.dll程序集的引用,并从Microsoft.VisualBasic.ApplicationService.WindowsFormsApplicationBase类继承一个自定义类。该类提供了三个用于管理实例的重要成员:
    1)  IsSingleInstance属性:允许启用单实例应用程序,在构造函数中将该属性设置为true.
    2)  在应用程序启动时重写OnStartup()方法,在此方法中创建WPF应用程序对象.
    3)  当另一个应用程序实例启动时触发OnStartupNextInstance()方法,此方法提供了访问命令行参数的功能。此时,可以调用WPF应用程序类中的方法来显示一个新窗口,而不创建另一个应用程序。
    下面是派生自Microsoft.VisualBasic.ApplicationService.WindowsFormsApplicationBase类的自定义类的代码:
    public class SingleInstanceApplicationWrapper:Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
    {
        public SingleInstanceApplicationWrapper()
        {
            this.IsSingleInstance = true;
        }
    
        private App app;
        protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs eventArgs)
        {
            app = new App();
            app.Run();
            return false;
        }
    
        protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs eventArgs)
        {
            if (eventArgs.CommandLine.Count > 0)
            {
                app.ShowDocument(eventArgs.CommandLine[0]);
            }
        }
    }
    View Code

    上面代码中的App是自定义的WPF应用程序类,下面是App类的代码:

    public class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            MainWindow mainWindow = new MainWindow();
            this.MainWindow = mainWindow;
            mainWindow.Show();
            if (e.Args.Length > 0)
            {
                ShowDocument(e.Args[0]);
            }
        }
    
        public void ShowDocument(string filename)
        {
            try
            {
                Document doc = new Document();
                doc.Title = filename;
                doc.Owner = this.MainWindow;
                doc.Show();
                doc.Activate();
            }
            catch
            {
                MessageBox.Show("Could not load document.");
            }
        }
    }
    View Code

    现在还需要定义一个应用程序入口,因为应用程序需要在App类之前创建SingleInstanceApplicationWrapper类,应用程序需要使用传统的Main()方法来启动,而不能使用App.xaml文件,下面是所需的代码:

    public class Startup
    {
        [STAThread]
        public static void Main(string[] args)
        {
            SingleInstanceApplicationWrapper wrapper = new SingleInstanceApplicationWrapper();
            wrapper.Run(args);
        }
    }
    View Code

    这三个类构成了单实例WPF应用程序的基础,使用这一基本框架模型,可以创建出更加完善的应用程序。

  8. 程序集资源
    有多种方法可以使用资源,低级的方法是检索包装数据的StreamResourceInfo对象,然后再决定如何使用该资源。可以通过代码使用静态的Application.GetResourceStream()方法,完成该工作。下面的代码为winter.jpg图像获取StreamResourceInfo对象:
    StreamResourceInfo sri = Application.GetResourceStream(new Uri("images/winter.jpg", UriKind.Relative));

    如果希望在WPF的Image元素中显示hills.jpg图像,可以使用下面的标记:

    <Image Source="images/LuFei.jpg"></Image>

    可以使用代码完成相同的工作,对于Image元素,只需要将Source属性设置为BitmapImage对象,该对象使用Uri确定希望显示的图像的位置,如下所示:

    img.Source = new BitmapImage(new Uri("images/LuFei.jpg",UriKind.Relative);
  9. pack URI
    WPF使用pack URI语法寻址编译过的资源,pack URI语法来自XPS标准,三个逗号实际上是三个转义的斜杠,以下是使用绝对Uri设置图像:
    img.Source = new BitmapImage(new Uri("pack://application:,,,/images/LuFei.jpg"));

    使用pack URI语法可以检索嵌入到另一个库中的资源,对于这种情况,需要使用下面的语法:

    pack://application:,,,/AssemblyName;component/ResourceName

    例如,如果图像被嵌入到一个引用的名称为ImageLibrary的程序集中:

    img.Source = new BitmapImage(new Uri("pack://application:,,,/ImageLibrary;component/images/LuFei.jpg"));

    或者,可以使用相对的Uri:

    img.Source = new BitmapImage(new Uri("ImageLibrary;component/images/LuFei.jpg",UriKind.Relative));

    如果使用强命名的程序集,可以使用包含版本或公钥标记的限定程序集引用代替程序集的名称。使用分号隔离各部分信息,并在版本号数字之前添加字母v,例如:

    img.Source = new BitmapImage(new Uri("ImageLibrary;v1.25;component/images/LuFei.jpg",UriKind.Relative));

    下面的示例同时使用了版本号和公钥标记:

    img.Source = new BitmapImage(new Uri("ImageLibrary;v1.25;dc642a7f5bd64912;component/images/LuFei.jpg",UriKind.Relative));
  10. 内容文件
    当为能够理解资源的元素使用内容文件时,可以使用相同的URI系统。
  11. 本地化
    在WPF中,将XAML文件作为本地化单元(从技术上讲,是嵌入到应用程序中的编译过的BAML资源),如果希望支持三种不同的语言,需要包含三个BAML资源。WPF会根据执行应用程序的计算机的当前文化设置,选择正确的资源(从技术上讲,WPF是通过驻留用户界面线程的CurrentUICulture属性做出决定的)。
    • 为了在项目中支持本地化,只需要在项目的.csproj文件的第一个元素<PropertyGroup>中的任意一个地方,添加以下元素:<UICulture>en-US</UICulture>。它告诉编译器,应用程序的默认文化是U.S.English,一旦进行了这一修改,生成过程就会发生变化,在下一次编译应用程序时,会生成一个名为en-US的子文件夹。在此文件夹中包含的是一个附属程序集,它和应用程序的名称相同,而且扩展名为.resources.dll。该程序集包含了应用程序的所有编译过的BAML资源,以前这些资源包含在主应用程序的程序集中。 现在,当运行应用程序时,公共语言运行时会根据计算机的区域设置自动在正确的目录中查找附属程序集,并加载正确的本地化了的资源。因此,如果希望为更多的文化添加应用程序本地化支持,只需要添加更多的子文件夹和附属程序集,而不干扰原来的可执行的应用程序。
    • 如何创建其它文化的附属程序集,WPF提供了一种解决方法,但需要手动执行几次Visual Studio命令行工具。
      • 为所有需要进行本地化的元素添加Uid特性,UID 用于跟踪对文件进行的更改和标识必须要进行翻译的项。不只是元素的文本需要进行本地化,还需要对元素的其它属性进行本地化,如:Fonts、FintSize、Margin、Padding和Alignment类属性,在WPF中,每个需要对其进行本地化的属性都使用System.Windows.LocalizabilityAttribute进行修饰。 我们不需要手动的为每一个元素添加Uid特性,而是可以在Visual Studio命令行中启动MSBuild工具自动的为每一个元素添加Uid特性,如:msbuild /t:updateuid ApplicationName.csproj 。如果想检查应用程序中的所有元素是否都已被Uid特性所标记,可以使用MSBuild,如:msbuild /t:checkuid ApplicationName.csproj 。当使用MSBuild生成Uid时,Uid与相应元素的名称进行匹配,如果元素没有名称,MSBuild会根据类的名称,在后面加上数字后缀来生成Uid。如:
        <Button x:Uid="btnTopLeft" Name="btnTopLeft" Grid.Row="0" Margin="3" Content="上左"></Button>
        <Button x:Uid="Button_2" Grid.Row="1" Margin="3" Content="下左"></Button>

        QQ图片20140802115106



原文地址:https://www.cnblogs.com/jiao1855/p/3879611.html