2010-05-14 31 views
6

我在C#.NET下的表單模態存在問題。假設我的主要形式爲#0(請參閱下圖)。該表格代表主要申請表格,用戶可以在其中執行各種操作。但是,有時需要打開額外的非模態表單來執行支持任務的其他主要應用程序功能。假設這是圖像中的#1形式。在這個#1表單上可能會打開幾個額外的模式形式(圖像中的#2表單),最後還有一個進度對話框,顯示一個長時間的操作進度和狀態,這可能需要很少的時間分鐘到幾個小時。問題在於,除非關閉所有模態窗體(圖像中的#2),否則主窗體#0無法響應。我需要在這種情況下主要的#0格式可以運行。但是,如果您在表單#2中打開非模式表單,則可以使用模式2表單和新創建的非模式表單進行操作。我需要主窗體#0和窗體#1與其所有子窗體之間的相同行爲。可能嗎?或者我做錯了什麼?也許有某種解決辦法的,我真的不希望改變這一切ShowDialog的調用顯示...WinForms編程 - 模態和非模態表單問題

Image http://img225.imageshack.us/img225/1075/modalnonmodalproblem.png

+2

您是否要求創建一個僅適用於其他表單之一的表單? – SLaks 2010-05-14 14:21:14

+0

我希望主窗體#0在有一些額外的模態子窗體(#2)打開非模態窗體#1時會保持響應。 – Povilas 2010-05-14 14:29:08

回答

12

模態窗體完成「模態」的意思,他們禁用應用程序中的所有其他窗口。這很重要,你的程序處於危險的狀態。你有一大塊代碼正在等待關閉對話框。真的不好的事情可能發生,如果其他窗口沒有被禁用。就像用戶可以再次啓動模式對話框一樣,現在您的代碼嵌套了兩次。或者她可以關閉對話框的所有者窗口,現在它突然消失。

這些是如果您在循環內調用Application.DoEvents()時遇到的確切類型的問題。哪種方式可以讓表單在不禁用其他窗口的情況下表現模態。例如:

Form2 mDialog; 

    private void button1_Click(object sender, EventArgs e) { 
     mDialog = new Form2(); 
     mDialog.FormClosed += (o, ea) => mDialog = null; 
     mDialog.Show(this); 
     while (mDialog != null) Application.DoEvents(); 
    } 

這是危險

當然,最好的方式是使用模式形式,以避免麻煩。如果你不想要一個模態形式,那麼就不要使它成爲模態,使用Show()方法。訂閱它的FormClosing事件知道它即將關閉:

private void button1_Click(object sender, EventArgs e) { 
     var frm = new Form2(); 
     frm.FormClosing += new FormClosingEventHandler(frm_FormClosing); 
     frm.Show(); 
    } 

    void frm_FormClosing(object sender, FormClosingEventArgs e) { 
     var frm = sender as Form2; 
     // Do something with <frm> 
     //... 
    } 
+0

謝謝你的回答,我想我可以使用一個單獨的GUI線程,因爲主窗體#0和窗體#1基本上都是自己的生活,並且不會互相影響。表格#1可能甚至是一個單獨的應用程序。 我不能將ShowDialog()更改爲Show(),因爲我需要模態窗體,但只能在窗體#1上下文中使用。用戶無法繼續使用表單#1(僅適用於表單#1),直到從表單#1打開的模式表單未關閉。 – Povilas 2010-05-20 06:57:23

3

,想到會是這樣的第一件事。當您啓動表單2時,您可以禁用表單1,然後讓表單1處理第二個表單的關閉事件以重新啓用自身。您不會使用顯示對話框打開模式2。

現在請記住,從用戶角度來看,這將是相當繁瑣的,你可以看看做一個MDI應用程序來獲得一個容器內的所有窗口。

0

直到在同一進程空間中的任何模態對話框都關閉後,您的主窗體纔會響應。這沒有工作。

0

它看起來對我來說,你可以使用MDI應用程序設置窗體#0 IsMdiContainer屬性爲true。

然後,你可以做一些事情一樣:

public partial class Form0 { 
    public Form0 { 
     InitializeComponent(); 
     this.IsMdiContainer = true; // This will allow the Form #0 to be responsive while other forms are opened. 
    } 

    private void button1_Click(object sender, EventArgs e) { 
     Form1 newForm1 = new Form1(); 
     newForm1.Parent = this; 
     newForm1.Show(); 
    } 
} 

使用ShowDialog(),你在你的問題說會讓所有的形式Modal = true

根據定義,一個模態的形式是:

當有模式地顯示的形式,可以除了模式窗體上的對象發生沒有輸入(鍵盤或鼠標點擊)。在輸入其他表單之前,程序必須隱藏或關閉模式表單(通常是響應某些用戶操作)。模態顯示的表單通常用作應用程序中的對話框。

您可以使用此屬性[(Modal)]來確定從方法或屬性獲取的窗體是否以模態方式顯示。

因此,只有當您需要用戶的即時幫助/交互時纔會使用模式形式。否則,使用模態形式會讓您相信您可能會遇到錯誤的方向。

如果你不希望你的主窗體是一個MDI容器,那麼也許使用多線程是一個簡單的解決方案。BackgroundWorker類是你想實現的關鍵。因此,在我看來就像一個設計的氣味......

  • 什麼是你想做的事,除了讓你的主要形式響應的,等
  • 你這是什麼做的?

解釋你要做的事情,我們可能能夠完全引導你進入正確的方向,或者至少是更好的方向。

+0

謝謝你的回答,我會盡力解釋更好。 MDI或將ShowDialog()更改爲Show()不會爲我解決這個問題,因爲我需要模態窗體(自定義數據編輯器),並且用戶無法繼續,直到他沒有完成當前的窗體爲止,但我需要模式才能工作在形式#1上下文中。在表單#1上,用戶正在處理稍後在主窗體#0上需要的一些數據。基本上,主要形式#0和形式#1生活在他們自己的生活中,形式#1甚至可以是獨立的應用程序。 #0從少數單身物體獲取數據,其中#1形式正在更新數據。 – Povilas 2010-05-20 06:48:55

+0

一年中有一半時間一切正常,但由於新的需求急速增加,我有一種情況,一個自定義數據編輯器的工作可能需要幾個小時。所以我認爲我可以使用Hans Passant的建議 - 一個單獨的GUI線程。並通過少數單例對象同步數據。 – Povilas 2010-05-20 06:49:19

-1

其實答案很簡單。嘗試

newForm.showDialog(); 

這將打開一個新窗體,而父窗體不可訪問。