【WPF學習】第二十七章 Application類的任務

  上一章介紹了有關WPF應用程序中使用Application對象的方式,接下來看一下如何使用Application對象來處理一些更普通的狀況,接下倆介紹如何初始化界面、如何處理命名行參數、如何處理支付窗口之間的交互、如何添加跟蹤文檔以及如何建立單示例應用程序。數組

1、顯示初始化界面安全

   WPF應用程序的運行速度快,但並不能在瞬間啓動。當第一次啓動應用程序時,會有一些延遲,由於公共語言運行時(Common Language Runtime,CLR)首先須要初始化.NET環境,而後啓動應用程序。app

  這一延遲未必成爲問題。一般,只須要經歷很短的時間,就會出現第一個窗口,但若是具備更耗時的初始化步驟,或者若是隻是但願經過顯示打開的圖像應用程序顯得更加專業,這時可以使用WPF提供的簡單初始界面特性。ide

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

  (1)爲項目添加圖像文件(一般是.bmp、.png或.jpg文件)。ui

  (2)在Solution Explorer中選擇圖像文件。this

  (3)將Build Action修改成SplashScreen。spa

  下次運行應用程序時,圖像會當即在屏幕中央顯示出來。一旦準備好運行時環境。並且Application_Startup方法執行完畢,應用程序的第一個窗口就將顯示出來,這時初始化界面圖像會很快消失(約需300毫秒).操作系統

  該特性聽起來很簡單,事實上也確實如此。只須要記住顯示的初始化界面沒有任何裝飾,在它周圍沒有窗口邊框,全部由你決定是否爲初始界面圖像添加邊框,也沒法經過顯示一系列的多幅圖像或動畫讓初始化圖像顯得更富有想象力的效果。若是但願獲得這種效果,須要採用傳統方法:建立在運行初始化代碼的同事顯示你所但願的圖像界面的啓動窗口。命令行

  順便提一下,當添加初始界面時,WPF編譯器會自動生成的App.g.cs文件添加與下面的相似的代碼:

SplashScreen splashScreen = new SplashScreen("images/blue.jpg");
//Show the splash screen
//The true parameter sets the splashScreen to fade away automatically
//after the first window appears
splashScreen.Show(true);

//Start the application
AssemblyResources.App app = new AssemblyResources.App();
app.InitializeComponent();
app.Run();
//The splash screen begins ites automatic fade-out now.

  也可自行編寫這一剪短邏輯,而不死使用SplashScreen 生成操做。但有一點須要指出,能夠改變的惟一細節是初始界面褪去的速度。爲此,須要項SplashScreen.Show()方法傳遞false(從而使WPF不會自動淡入初始化界面)。而後由你負責經過調用SplashScreen.Close()方法在恰當的時機隱藏初始界面,並提供TimeSpan值來指示通過多長時間淡出初始化界面。

2、處理命令行參數

  爲處理命令行參數,須要相應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();
        }
    }
<Application x:Class="LoadFromCommandLine.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Startup="App_Startup">
    <Application.Resources>
         
    </Application.Resources>
</Application>
App.xaml

  上面的方法初始化主窗口,而後當App_Startup()方法結束是顯示主窗口。上面的代碼假定FileViewer類有名爲LoadFile()的共有方法。這只是一個示例,它只讀取並顯示指定文件的文本。

3、訪問當前Application對象

  經過靜態的Application.Current屬性,可在應用程序的任何位置獲取當前應用程序實例,從而在窗口之間進行基本交互,由於任何窗口均可以訪問當前Application對象,並經過Application對象,並經過Application對象獲取主窗口的做用:

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

  固然,若是但願訪問在自定義主窗口類中添加的任意方法、屬性或事件,須要將窗口對象轉換爲正確類型。若是主窗口的自定義類MainWindow的實例,可以使用與下面相似的代碼:

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

  在窗口中還能夠檢查Application.Windows集合的內容,該屬性提供了全部當前打開窗口的引用:

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

  實際上,大多數應用程序一般使用一種更具結構化特色的方式在窗口之間進行交互。若是有幾個長時間運行的窗口同事打開,而且它們之間須要以某種方式進行通訊,在自定義應用程序類中保存這些窗口的引用可能更有意義。這樣,總能夠找到所需的窗口。與此相似,若是有基於文檔的應用程序,那麼可選擇建立跟蹤文檔窗口的集合,而不是跟蹤其餘內容。

4、在窗口之間進行交互

  整如在前面已經看到的,自定義應用程序類是放置響應不一樣應用程序事件的代碼的好地方。應用程序類還能夠很好地達到另外一個目的:保存重要窗口的引用,使一個窗口可訪問另外一個窗口。

  例如,假設但願跟蹤應用程序使用的全部文檔窗口。爲此,可在自定義應用程序類中建立專門的集合。下面是使用泛型列表集合保存一組自定義窗口對象的示例。在這個示例中,每一個文檔窗口由名爲Document類的實例表示:

 public partial class App : Application
    {
        private List<Document> documents = new List<Document>();
        
        public List<Document> Documents
        {
            get { return documents; }
            set { documents = value; }
        }
    }

  如今,當建立新文檔時,只須要記住將其添加到Documents集合中便可。下面是響應按鈕單擊事件的事件處理程序,該事件處理程序完成了所需的工做:

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

  一樣,也可在Document類中響應Window.Loaded類這些事件,以確保當建立文檔對象時,總會在Documents集合中註冊該文檔對象。

  如今,可在代碼的其餘任何地方進行集合來遍歷全部文檔,並使用公有成員。在該例中,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() + ".");
            }            
        }
<Window x:Class="WindowTracker.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WindowTracker" Height="300" Width="300"
    >
    <StackPanel>
      <Button Click="cmdCreate_Click" Margin="10,10,10,5" Name="cmdCreate">Click to Create a Document</Button>
      <Button Click="cmdUpdate_Click" Margin="10,5,10,10" Name="cmdUpdate">Click to Refresh the Documents</Button>
    </StackPanel>
</Window>
MainWindow.xaml
<Window x:Class="WindowTracker.Document"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WindowTracker" Height="78" Width="209"
    >
    A new document.
</Window>
Document.xaml
public partial class Document : Window
    {
        public Document()
        {
            InitializeComponent();
        }

        public void SetContent(string content)
        {
            this.Content = content;
        }
    }
Document.xaml.cs

  下圖顯示了最終效果圖。最終結果談不上華美,但這種交互方式值得注意——演示了一種經過自定義應用程序類在窗口之間進行交互的安全規範的方式。這種方式比使用Window屬性要好,由於是強類型,只包含Document窗口(而不是包含窗口應用程序中全部窗口的集合)。經過這種方式還可以使用另外一種更有用的方式對窗口進行分類。例如,可以使用字典集合,經過鍵名更方便地查找文檔。在基於文檔的引用程序中,可經過文件名來索引集合中的窗口。

 

 5、單實例應用程序

  一般,只要願意就能夠加載WPF應用程序的任意多個副本。某些狀況下, 這種設計時很是合理的。但在另一些狀況下,這可能會成爲問題,當構建基於文檔的應用程序時更是如此。

  對於單實例應用程序,WPF自己並未提供自帶的解決方法,但可以使用幾種變通方法。基本技術時當觸發Application.Startup事件時,檢查另外一應用程序實例是否已在運行。最簡單的方法是使用全局的mutex對象(mutex對象時操做系統提供的用於進程間通訊的同步對象)。這種方法很簡單,但功能有限。最重要的是,應用程序的新實例沒法與已經存在的實例進行通訊。對於基於文檔的應用程序而言這確實是一個問題,由於新實例可能須要告訴已經存在的應用程序實例打開某個特定的文檔(若是該文檔是經過命令行參數傳遞的)。

相關文章
相關標籤/搜索