2010-03-12 2 views
15

응용 프로그램을 만들고 있는데 오랜 프로세스가 진행될 때 나타나는 진행률 창을 구현하고 싶습니다.두 번째 winform을 비동기 적으로 열지 만 상위 폼의 자식으로 여전히 동작합니까?

저는 기본 양식을 사용하여 내 응용 프로그램을 만든 표준 Windows 양식 프로젝트를 만들었습니다. 진행 창으로 사용할 새 양식을 만들었습니다.

난 (함수에서) 진행 창을 열 때 문제는 사용하여 발생 :

이 명령이 발생
ProgressWindow.ShowDialog(); 

, 초점은 진행 창에 내가 지금 돌이가의 윈도우의 가정 이벤트 처리 중. 단점은 메인 폼에서의 오랜 동작의 실행을 막는 것입니다.

내가 사용하여 진행 창을 열면 :

ProgressWindow.Show(); 

그런 다음 윈도우가 제대로 열리고 이제 기본 폼의 실행을 차단하지 않습니다하지만 아이 (모달) 창으로 행동하지 않는해야 , 즉, 기본 폼을 선택할 수 있습니다, 등 부모를 중심으로하지 않습니다.

어떤 아이디어가 새 창을 열 수 있지만 기본 폼에서 처리를 계속할 수 있습니까?

답변

9

다른 작업자 스레드 (예 : 배경 작업자)로 길어진 작업을 시작하는 것이 좋습니다. 그런 다음 ShowDialog()을 사용하여 양식을 표시하고 표시된 대화 상자가 닫히면 대화 상자가 닫힙니다.

다음은 샘플입니다. 여기서는 두 가지 양식 (Form1Form2)이 있다고 가정합니다. Form1에 나는 도구 상자에서 BackgroundWorker을 당겼습니다. 그런 다음 이벤트 (BackgroundWorker)를 내 양식의 이벤트 핸들러에 연결했습니다. 또 다른 옵션

public partial class Form1 : Form 
{ 
    public Form1() { 
     InitializeComponent(); 
    } 

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { 
     Thread.Sleep(5000); 
     e.Result = e.Argument; 
    } 

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { 
     var dlg = e.Result as Form2; 
     if (dlg != null) { 
      dlg.Close(); 
     } 
    } 

    private void button1_Click(object sender, EventArgs e) { 
     var dlg = new Form2(); 
     this.backgroundWorker1.RunWorkerAsync(dlg); 
     dlg.ShowDialog(); 
    } 
} 
+0

아 예, 배경 종업원을 완전히 잊었다! –

3

:

사용 ProgressWindow.Show() & 모달 창 동작을 직접 구현하는 다음 대화 상자를 이벤트를 처리하고 표시하는 코드입니다. parentForm.Enabled = false, 직접 양식을 배치하십시오.

+0

흠, 내가 "최고"라고 생각했기 때문에 (ShowDialog()는 오랫동안 스택에 앉아서 DoEvents()를 호출하기 때문에 기본적으로 해킹 된 것으로 간주하기 때문에) "쉽지"않다. (왜냐하면 네가 에뮬레이션해야하기 때문이다. 모달 대화 상자 동작). 그래서 당신이 그것의 더 쉬운 생각한다면, 나는 그것을 위해 간다고 말할 것입니다. –

3

다른 프로젝트에서 이와 비슷한 것을 구현했습니다.

public partial class NotificationForm : Form 
{ 
    public static SynchronizationContext SyncContext { get; set; } 

    public string Message 
    { 
     get { return lblNotification.Text; } 
     set { lblNotification.Text = value; } 
    } 

    public bool CloseOnClick { get; set; } 

    public NotificationForm() 
    { 
     InitializeComponent(); 
    } 

    public static NotificationForm AsyncShowDialog(string message, bool closeOnClick) 
    { 
     if (SyncContext == null) 
      throw new ArgumentNullException("SyncContext", 
              "NotificationForm requires a SyncContext in order to execute AsyncShowDialog"); 

     NotificationForm form = null; 

     //Create the form synchronously on the SyncContext thread 
     SyncContext.Send(s => form = CreateForm(message, closeOnClick), null); 

     //Call ShowDialog on the SyncContext thread and return immediately to calling thread 
     SyncContext.Post(s => form.ShowDialog(), null); 
     return form; 
    } 

    public static void ShowDialog(string message) 
    { 
     //Perform a blocking ShowDialog call in the calling thread 
     var form = CreateForm(message, true); 
     form.ShowDialog(); 
    } 

    private static NotificationForm CreateForm(string message, bool closeOnClick) 
    { 
     NotificationForm form = new NotificationForm(); 
     form.Message = message; 
     form.CloseOnClick = closeOnClick; 
     return form; 
    } 

    public void AsyncClose() 
    { 
     SyncContext.Post(s => Close(), null); 
    } 

    private void NotificationForm_Load(object sender, EventArgs e) 
    { 
    } 

    private void lblNotification_Click(object sender, EventArgs e) 
    { 
     if (CloseOnClick) 
      Close(); 
    } 
} 

당신은 당신의 GUI 스레드에서 어딘가에서 SyncContext를 설정해야합니다 사용하기 :이 양식을 사용하면 작업자 스레드 내에서 모달 대화 상자를 팝업 할 수 있습니다

NotificationForm.SyncContext = SynchronizationContext.Current; 
관련 문제