2012-03-27 6 views
1

다른 응용 프로그램 (이 경우 메모장)을 시작하는 양식 인 주 스레드가 있고 메모장을 기다리는 BackgroundWorker를 생성합니다. 닫혀 야한다. 닫힌 상태에서 BackgroundWorker는 사용자에게 최상위로 표시 할 다른 Form을 표시합니다. 이 양식은 모달이 아니어야 사용자가 주 스레드 대화 상자의 일부 단추를 누를 수 있습니다. 문제는이 폼 (Form2, BackgroundWorker에서)이 TopMost가 아니라는 것입니다. 사실 true로 설정 한 경우에도 마찬가지입니다. F5를 누르면 작동하지만 ClickOnce 응용 프로그램으로 내 서버에 게시하면 form2는 더 이상 TopMost가 아닙니다. 나는 Form2.Topmost = true, BringToFront, Activate, "MakeTopMost"를 What is powerful way to force a form to bring front?에서 지치 셨다. 아무 것도 작동하지 않는 것 같다.Windows.Form ClickOnce가 활성화되어 게시 될 때 workerthread에서 최상위 호출이 작동하지 않습니다.

심지어 메인 폼의 핸들을 얻고 그것을 form2의 부모로 사용하려고했지만 "InvalidOperationException : Cross-thread operation not valid : 컨트롤 'Form2'이외의 스레드에서 액세스했습니다. 스레드가 생성되었습니다. "

public partial class Form1 : Form 
{ 
    System.Diagnostics.Process p = new System.Diagnostics.Process(); 
    private BackgroundWorker endApplicationBackgroundWorker= new BackgroundWorker(); 

    public Form1(string[] args) 
    { 
     endApplicationBackgroundWorker.DoWork += new DoWorkEventHandler(endApplicationBackgroundWorker_DoWork); 

     p.StartInfo.FileName = "notepad"; 
     p.Start(); 

     endApplicationBackgroundWorker.RunWorkerAsync(); 

     //Quit here so we can accept user inputs (button pushes ..) 
    } 

    private void endApplicationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     p.WaitForExit(); 

     Form2 form2 = new Form2(); 
     form2.TopMost = true; 

     System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName(form1ProcessName); 
     if (procs.Length != 0) 
     { 
      IntPtr hwnd = procs[0].MainWindowHandle; 
      if (form2.ShowDialog(new WindowWrapper(hwnd)) == DialogResult.OK) 
      { 
       // process stuff 
      } 
     } 

     this.Close(); 
    } 
} 

다른 아이디어 : 여기

는 코드인가? 아니면 누군가 내 코드를 고칠 수 있습니까? 저는 몇 주 동안이 문제를 다루었 고 어리둥절하게 지내 왔습니다.

감사합니다.

답변

1

RunWorkerAsync 프로 시저를 호출 한 후 BackgroundWorker의 DoWork 메서드에서 수행하는 모든 작업은 UI 스레드에서 실행되지 않지만 코드는 백그라운드에서 양식을 만듭니다.

양식 UI 요소, 그래서이 작동하지 않습니다 코멘트에서

private void endApplicationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    Form2 form2 = new Form2(); 
    form2.TopMost = true; 
    // etc.. 
    if (form2.ShowDialog(new WindowWrapper(hwnd)) == DialogResult.OK) 
    { 
    // process stuff 
    } 
} 

, 당신은 두 번째 폼을 표시하기 위해 RunWorkerCompleted 이벤트에 가입해야합니다. 또한, 당신도, 당신이 ShowDialog 전화없이 살아 Form2를 유지하려고 하나 때문에 Close 메소드를 호출하기 때문에 기본 폼은 폐쇄되어야 할 때 알리도록 두 번째 양식의 Form_Closing() 이벤트에 가입하려고 할 수 없습니다

public Form1(string[] args) 
{ 
    endApplicationBackgroundWorker.DoWork += 
    new DoWorkEventHandler(endApplicationBackgroundWorker_DoWork); 
    endApplicationBackgroundWorker.RunWorkerCompleted += 
    new RunWorkerCompletedEventHandler(endApplicationBackgroundWorker_RunWorkerCompleted); 

    p.StartInfo.FileName = "notepad"; 
    endApplicationBackgroundWorker.RunWorkerAsync(); 
} 

private void endApplicationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    p.Start(); 
    p.WaitForExit(); 
} 

private void endApplicationBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    Form2 form2 = new Form2(); 
    form2.TopMost = true; 
    form2.FormClosing += new FormClosingEventHandler(form2_FormClosing);  
    form2.Show(this); 
} 

private void form2_FormClosing(object sender, FormClosingEventArgs e) 
{ 
    this.BeginInvoke(new MethodInvoker(delegate { this.Close(); })); 
} 
+0

사과, 정확합니다. 중요하지 않은 코드를 잘라내는 과정에서 코드를 잘못된 위치에 놓았습니다. WaitForExit은 BackgroundWorker에 있습니다 (위의 코드를 업데이트했습니다). 이는 백그라운드 작업자가 대기 할 수있는 반면 주 스레드는 버튼 클릭을 허용 할 수 있습니다. 나는 form2가 열려있는 동안 사용자가 메인 폼에서 같은 버튼을 클릭 할 수 있기를 원한다. – Tizz

+0

@Tizz DoWork 메소드에서 필요한 것은'p.Start'와'p.WaitForExit'이며,'RunWorkerCompleted' 이벤트에 가입하고 거기서'Form2' 물건 전부를 이동하는 것처럼 보입니다. 이 시점에서 백그라운드 스레드에서 아무 것도 일어나지 않고 UI 스레드에서 사용자의주의를 요구하고있는 것처럼 보입니다. – LarsTech

+0

동일한 BackgroundWorker 스레드에서 RunWorkerCompleted가 아닙니까? 나는 동일한 결과를 얻을 수 없을까? – Tizz

0

또 다른 해결 방법은 맨 위를 false로 설정 한 다음 다시 true로 설정하는 것입니다. 그것은 이상하지만 작동합니다. ppaForm 당신이 설명 here을 찾을 수에 대한 PerPixelAlphaForm을,이 경우에

for (int i = 0; i < 50; i++) 
{ 
    ppaForm.SetBitmap(bitmap, (byte)(255 - i * 5)); 
    ppaForm.Show(); 
    ppaForm.TopMost = false; 
    ppaForm.TopMost = true; 

    Thread.Sleep(6); 
} 

: 그래서 코드는 형태에 대해 다음과 같은 것이 될 수있는 간단한 배경 스레드에서 oppacity 내림차순으로 표시 될 수 있습니다.