C# WinForm得到主窗體——如何判斷哪一個是主窗體

一. 關於定義

主窗體的定義通常有兩種。第一種就是通常上,廣泛意義認爲是程序中第一個被建立出來的窗體,可是因爲一些程序在顯示主窗體以前會有一個登陸或者引導窗體,在使用完了以後直接隱藏而不是關閉。這個時候,主窗體並不會是第一個窗體。因此,第二種說法就是說,包含了軟件總體功能的展現性界面所在的窗體,咱們稱之爲主窗體。函數

而在本文中,全部敘述中所指的主窗體都是指的是第二種定義的主窗體工具

二. WPF中的主窗體與引子

對於 WPF 用戶來講,咱們能夠直接使用:測試

Window window = Application.Current.MainWindow;

而對於 Winform 來講就比較麻煩,由於它並無提供任何得到主窗體的接口屬性(?)。網上有的文章說能夠經過spa

Process.GetCurrentProcess().MainWindowHandle

來判斷當前的窗體是否是主窗體,通過博主的測試發現,這個方法並不能很好的判斷。通過測試覈實 MainWindowHandle 有以下特色:.net

1. 首先,雖然這個屬性的名稱是 MainWindowHandle,可是不能在某個進程中使用這個屬性來判斷哪個窗體是進程的主窗體;進程之間得到主窗體能夠考慮使用這個方式(但不是特別好用),因此這個方法適合作運行外接程序時使用,而且僅當進程有圖形界面(有窗體)時,該進程才具備與其關聯的主窗口。若是關聯進程沒有主窗口,則 MainWindowHandle 值爲零。若是剛啓動了一個進程,而且想使用其主窗口句柄,則須要考慮使用 WaitForInputIdle 方法讓該進程完成啓動,從而確保建立了主窗體窗口的句柄。不然,將引起異常。線程

通常避免這個異常的代碼以下:code

Process startProcess=... //得到建立一個進程
startProcess.WaitForInputIdle(); Intptr handle=startProcess.MainWindowHandle;

2. 若是這個函數是在 Show(null) 或者 Application.Run(Form) 中的窗體打開的,那麼這個值是這個打開窗體的句柄;若是這個函數是在 ShowDialog(null) 或者 ShowDialog(parentForm) 或者 Show(parentForm) 的時候,這個值是父級窗體的句柄;orm

 

具體的文章參考能夠見下面地址連接的文章:對象

參考文章blog

三. 三種博主的方法

博主目前有以下面所述的三種處理方式,若是有更好的方式能夠在評論中和博主交流。


  • 經過公共配置類的接口方式

原理:使用 Form 做爲一個公共配置類的接口,全部的上端都經過這個公共配置類來訪問主窗體的對象。

這邊的公共配置類的代碼通常爲:

/// <summary>
/// 公共配置類 /// </summary>
public class CommonBase { /// <summary>
    /// 主窗體對象的引用 /// </summary>
    public static Form MainForm { get; set; } }

上端調用代碼,經過在使用窗體的時候,將主窗體注入到公共配置類的接口中:

//建立主窗體
Form1 form1 = new Form1(); //設置主窗體
CommonBase.MainForm = form1; //添加到消息循環
Application.Run(form1);

因爲這個公共配置類 CommonBase 會做爲全部類的下端,因此全部的類均可以訪問到這個主窗體。


  • 使用派生 AppliactionContext 的方式

原理:Application.Run 有多種重載的方式,咱們通常使用的是

//
// 摘要: // 在當前線程上開始運行標準應用程序消息循環,並使指定窗體可見。 //
// 參數: // mainForm: // 一個 System.Windows.Forms.Form,它表明要使之可見的窗體。 //
// 異常: // T:System.InvalidOperationException: // 主消息循環已在當前線程上運行。
public static void Run(Form mainForm);

這邊傳遞的是一個窗體的對象;而這個 Run 方法還有一個別的重載:

// 摘要: // 在特定的 System.Windows.Forms.ApplicationContext 中,在當前線程上開始運行標準應用程序消息循環。 //
// 參數: // context: // 一個 System.Windows.Forms.ApplicationContext,應用程序將在其中運行。 //
// 異常: // T:System.InvalidOperationException: // 主消息循環已在此線程上運行。
public static void Run(ApplicationContext context);

這個重載須要一個派生自 ApplictionContext 的對象。經過派生這個上下文對象,並在其中包裝一個主窗體的對象,而後在這個派生的子類中給出獲取自身的靜態方法,讓用戶能夠得到這個派生類的全局實例,最好是使用單例的方式來獲取。接着,利用 AppliactionContext 中的 MainForm 屬性來得到註冊到 ApplicationContext 的主窗體。

下面給出一個派生類 MainFormContext 的代碼:

/// <summary>
/// 派生ApplicationContext的方法 /// </summary>
public class MainFormContext : ApplicationContext { /// <summary>
    /// 線程鎖 /// </summary>
    private static object objLock = new object(); /// <summary>
    /// 全局單例 /// </summary>
    private static MainFormContext context = null; /// <summary>
    /// 隱藏構造函數不讓外部調用建立 /// </summary>
    /// <param name="mainForm"></param>
    private MainFormContext(Form mainForm) : base(mainForm) { } /// <summary>
    /// 得到MainFormContext /// </summary>
    /// <param name="mainForm"></param>
    /// <returns></returns>
    public static MainFormContext GetInstance(Form mainForm = null) { if (mainForm == null) { return context; } //建立單例
        if (context == null) { lock (objLock) { if (context == null) { context = new MainFormContext(mainForm); } } } return context; } }

上端調用的代碼,建立包括 MainFormContext 的上下文,並使用 Application.Run(Application)進行執行:

//主窗體
Form1 form = new Form1(); //建立上下文
MainFormContext context = MainFormContext.GetInstance(form); //開啓消息循環
Application.Run(context);

  • 利用 Application.OpenForms 集合找到主窗體

原理:經過 Application.OpenForms 集合遍歷全部的呈打開展現的窗體對象,而後經過比對窗體的名稱(或者別的特色)來找到主窗體的 Form 類型的對象。

注意:網上不少的文章都說,Application.OpenForms[0] 就是主窗體。其實,按照第一大點的定義,若是在出現主窗體以前還有別的窗體建立而且沒有被關閉(銷燬),那麼這個 0 號序號的窗體就會是別的窗體(非主窗體)。這邊 Application.OpenForms 窗體的集合,是按照你在程序運行的過程當中建立顯示窗體的順序來進行排列的。

 

好比,主窗體的名稱 Text 爲 "MainForm",那麼用來得到主窗體的幫助類的代碼以下:

/// <summary>
/// 匹配得到主窗體的工具類 /// </summary>
public class MainFormHelper { public Form GetMainForm(string mainFormName= "MainForm") { if(string.IsNullOrEmpty(mainFormName)) { return null; } foreach(Form frm in Application.OpenForms) { if(frm.Text.Trim()== mainFormName) { return frm; } } return null; } }

四. 方法的缺陷

這邊三種方案都存在必定的問題:

1. 要建立一個額外的幫助類,而且這個類要是全部類的下端,若是有一個類是這個幫助類的下端,那麼這個類會訪問不到幫助類中的成員,也就是說不能訪問到主窗體的對象屬性;

2. 因爲這個幫助類是全部類的下端,因此這個配置類中的主窗體只能以窗體的 Form 基類出現,致使其餘的使用端不能直接使用主窗體具體類型的方法(須要轉換,甚至不能轉換);

3. 使用以前須要注入一次,操做和代碼都比較繁瑣;

五. 程序代碼下載

下載地址

相關文章
相關標籤/搜索