WPF高級教程(十)WPF程序的生命週期

介紹

就像每一個窗口對應一個Window類一樣,每一個WPF的應用程序對應一個Application類

生命週期

創建

WPF程序中,Application類的創建是由App.xaml中完成的,具體的代碼如下

<Application x:Class="TestProject.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Novc.ViPlex.Express" DispatcherUnhandledException="Application_DispatcherUnhandledException"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries> 
                <ResourceDictionary Source="/Novc.ViPlex.Express.Views;component/Themes/Converters.xaml"/>
                <ResourceDictionary Source="/Novc.ViPlex.Express.Views;component/Themes/Default/Generic.xaml"/>
                <ResourceDictionary Source="/Novc.ViPlex.Express.Views;component/Language/Language.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

其中比較關鍵的是指定了StartupUri

關閉

  • 在xaml中可以設置ShutdownMode
    在這裏插入圖片描述
  • 手動關閉應用程序需要:Application.Shutdown()

事件處理

我們可以在App.xaml.cs中監聽下面的事件
在這裏插入圖片描述
事件的處理可以有兩種方法,一種是在xaml中指定事件處理程序,就像給一個Button寫OnClick一樣,一種是直接在App.xaml.cs中複寫相應的事件處理程序,比如重寫OnStartUp

// 1. 關聯事件處理程序
// xaml
DispatcherUnhandledException="Application_DispatcherUnhandledException"
// cs文件
private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
    ...
}
// 2. 直接複寫
protected override void OnActivated(EventArgs e)
{
    base.OnActivated(e);
}
  • 需要注意 Application_DispatcherUnhandledException 這個方法沒有對應的基類方法可以複寫,只能通過xaml關聯
  • OnSessionEnding方法如果監聽,設置e.Cancel = true,則系統的關閉,註銷都會被阻止。

顯示初始Load圖片

在出現第一個窗口之前,我們可以設置一個圖片作爲過場加載動畫,做法是:

  1. 項目中加載一個圖片
  2. 設置圖片屬性,將 生成操作 屬性修改爲SplashScreen

處理命令行參數

我們的程序可以直接右鍵打開,也可以在命令行中添加命令打開。要想獲取命令行參數,需要在App_Satrtup事件中,使用StartEventArgs參數e,e.Args[0]獲取第一個參數。

Application的用處

獲取窗口實例

// 獲取應用程序實例
Application.Current
// 獲取主窗體
Application.Current.MainWindow
// 所有打開的窗口引用,注意窗口在集合中的位置不是固定的,不能通過一個數字索引來確定窗體
Application.Current.Windows

窗口間信息交互

  • 在Application類中可以保存重要窗口的引用,使得另一個窗口可以訪問他
// App類中可以保存全局的引用
// 定義
prop List<Document> Documents
// 在程序中任意位置使用
((App)Application.Current).Documents
// 在使用的時候可以把Document作爲所有要跟蹤的窗口的基類

單例應用程序

如果我們的應用程序只能打開一份,比較容易想到的方法是在StartUp方法中,判斷是否有應用程序已經打開,可以判斷進程,並且關閉本軟件。但是這種方法無法實現像word那樣,打開doc文件如果office已經打開就在當前實例中打開這個文件,原因是按照我們原來的方法,當打開軟件走到StartUp的時候,已經是新的應用程序了。要實現這樣的功能我們需要這樣的方法:

  1. 添加對於Microsoft.VisualBasic.dll的引用
  2. 新增一個類,繼承自 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
  3. 構造函數中設置IsSingleInstance爲true
  4. 複寫OnStartUp方法,創建WPF對象
  5. 複寫OnStartupNextInstance方法,調用原來的WPF APP去處理該方法中的啓動參數
public class SingleInstanceApplicationWrapper : 
    Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
{        
    public SingleInstanceApplicationWrapper()
    {
        // Enable single-instance mode.
        this.IsSingleInstance = true;
    }

    // Create the WPF application class.
    private WpfApp app;
    protected override bool OnStartup(
        Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
    {            
        string extension = ".testDoc";
        string title = "SingleInstanceApplication";
        string extensionDescription = "A Test Document";
        // Uncomment this line to create the file registration.
        // In Windows Vista, you'll need to run the application
        // as an administrator.            
        //FileRegistrationHelper.SetFileAssociation(
        //  extension, title + "." + extensionDescription);

        app = new WpfApp();
        app.Run();

        return false;
    }

    // Direct multiple instances
    protected override void OnStartupNextInstance(
        Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
    {
        if (e.CommandLine.Count > 0)
        {                
            app.ShowDocument(e.CommandLine[0]);
        }
    }
}

WPfApp類代碼:

public class WpfApp : System.Windows.Application
{
    protected override void OnStartup(System.Windows.StartupEventArgs e)
    {
        base.OnStartup(e);
        
        // Load the main window.
        DocumentList list = new DocumentList();
        this.MainWindow = list;
        list.Show();

        // Load the document that was specified as an argument.
        if (e.Args.Length > 0) ShowDocument(e.Args[0]);
    }

    // An ObservableCollection is a List that provides notification
    // when items are added, deleted, or removed. It's preferred for data binding.
    private ObservableCollection<DocumentReference> documents = 
        new ObservableCollection<DocumentReference>();
    public ObservableCollection<DocumentReference> Documents
    {
        get { return documents; }
        set { documents = value; }
    }        

    public void ShowDocument(string filename)
    {
        try
        {                
            Document doc = new Document();
            DocumentReference docRef = new DocumentReference(doc, filename);
            doc.LoadFile(docRef);                
            doc.Owner = this.MainWindow;
            doc.Show();
            doc.Activate();
            Documents.Add(docRef);
        }
        catch
        {
            MessageBox.Show("Could not load document.");
        }
    }
}   

使用StartUp啓動應用程序:

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

不需要傳遞參數的單例應用程序

如果只需要在多開的時候關閉當前應用並且將之前的激活,用下面的方法即可

private void App_Startup(object sender, StartupEventArgs e)
{

    //獲取欲啓動進程名
    string strProcessName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
    //檢查進程是否已經啓動,已經啓動則顯示提示退出程序。 
    if (System.Diagnostics.Process.GetProcessesByName(strProcessName).Length > 1)
    {
        RaiseOtherProcess();
        Application.Current.Shutdown();
        return;
    }

    Platform.Log.LogForNet.LogHelper.Init();
}

[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
/// <summary>
/// 激活已打開窗口
/// </summary>
public static void RaiseOtherProcess()
{
    Process proc = Process.GetCurrentProcess();
    foreach (Process otherProc in
        Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName))
    {
        if (proc.Id != otherProc.Id)
        {
            IntPtr hWnd = otherProc.MainWindowHandle;
            if (IsIconic(hWnd))
            {
                ShowWindowAsync(hWnd, 9);
            }
            SetForegroundWindow(hWnd);
            break;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章