2013-08-28 2 views
1

나는 C# 및 Winforms를 사용하여 응용 프로그램을 만들고 보관하며 지정한 위치에 폴더를 저장합니다. 보관 폴더는 입니다. BackgroundWorker은 폴더 경로를 입력으로 사용하고 zip 아카이브를 생성합니다. 다음 단계에서는 파일이 필요합니다. 지정된 위치에서 이동하는, 다시 파일이 충분히 큰 및 UI 스레드를 걸 수있는 내가 FileMove라는 이름의 또 다른 BackgroundWorker에에 코드를 이동로, 모든 것이 여기의 FileMove 어떤 진행 상황을보고하지 않는 것을 제외하고 잘 작동 보관 기능이 끝나자 마자 바로 전화하는 기능입니다. (내가 900-1,000메가바이트를 압축하고있어 같은) 파일 이동이 LABEL3 쇼 "저장 파일, ... 기다려주십시오"하고 오랜 시간 후에 시작으로BackgroundWorker가 파일 복사 진행률을보고하지 않습니다?

private void FileMove_DoWork(object sender, DoWorkEventArgs e) 
    { 
     label3.Text = "Saving file,please wait..."; 
     File.Move(temppath + @"\Output.jpg", savefilename); 
    } 

    private void FileMove_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     label3.Text = "Saving file,please wait... " + e.ProgressPercentage.ToString(); //This should show Progress Percentage but it doesn't. 
    } 

    private void FileMove_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     label3.Text = ("The folder has been successfully hidden."); 
     button1.Enabled = true; 
     button2.Enabled = true; 
     button3.Enabled = true; 
     this.ControlBox = true; 
    } 

내가 직면하고있어 문제는 곧 "폴더가 성공적으로 숨겨져 있습니다."라는 메시지가 나타납니다. ProgressChanged 이벤트 라벨도 백분율을 표시해야하지만 그렇지 않습니다. 잘못되었거나 잘못 표시된 곳을 지적하십시오. 도움이 될 것입니다.

+0

진행률을보고 할 수있게 설정 했습니까? - [this] (http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.workerreportsprogress.aspx) – Sayse

+0

예 Sayse, BackgroundWorker가 진행 상황을보고 할 수 있습니다. – PurpleXenon

+0

그럼 아마도 당신의 레이블이 UI 스레드에 있기 때문에, 당신은 [invoke it]해야합니다. (http://stackoverflow.com/questions/5192169/update-gui-using-backgroundworker?rq=1) – Sayse

답변

2

먼저 BackgroundWorker은 멀티 스레드 UI 앱에서 no-no 인 백그라운드 스레드에서 UI를 업데이트하려고합니다.

UI를 업데이트하려면 업데이트를 수행하기 위해 UI 스레드로 전환해야합니다. label3.InvokeRequired 다음 label3.Invoke (not Delegate.Invoke())

이에 대리자를 전달 사실 (현재 스레드에서 UI를 업데이트 할 수 없습니다 나타내는) 경우이 먼저 검사에 의해 당신은 매우 잘 알고 있어야 패턴입니다 이루어집니다 WinForms 개발 용. Control.Invoke MSDN 페이지에는이 패턴을 활용하는 샘플이 포함되어 있습니다.

두 번째로 을 주기적으로 호출해야 ProgressChanged 이벤트가 백분율 완료 값으로 실행됩니다.


다음은 샘플 앱입니다. Button, Label 및 BackgroundWorker가있는 폼이 WorkgerReportsProgress = true (및 보너스 포인트의 경우 WorkerSupportsCancellation = true) 인 것으로 가정합니다.

버튼을 클릭하면 5 초의 차단 작업이 시작된 다음 10 초의 차단 작업으로 전환됩니다 (도중에 진행 상황보고).

UI가 올바른 스레드에서 업데이트되도록 보장하는 도우미 메서드 InvokeIfRequired()에 유의하십시오. 이것을 지나치게 사용하면 해가 없습니다.

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

    private void button1_Click(object sender, EventArgs e) 
    { 
    if (backgroundWorker1.IsBusy) 
    { 

     label1.Text = "Reset!"; 
     backgroundWorker1.CancelAsync(); 
     return; 
    } 

    backgroundWorker1.RunWorkerAsync(); 
    } 

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
    label1.InvokeIfRequired(() => label1.Text = "Gettin busy"); 
    System.Threading.Thread.Sleep(5000); 

    for (int i = 0; i < 10; i++) 
    { 
     backgroundWorker1.ReportProgress(i*10); 
     System.Threading.Thread.Sleep(1000); 
    } 
    } 

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
    label1.InvokeIfRequired(() => label1.Text = "Done"); 
    } 

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
    label1.InvokeIfRequired(() => label1.Text = string.Format("{0}% done", e.ProgressPercentage)); 
    } 
} 

public static class InvokeExtensions 
{ 
    public static void InvokeIfRequired(this ISynchronizeInvoke control, MethodInvoker action) 
    { 
    if (control.InvokeRequired) 
    { 
     control.Invoke(action, null); 
    } 
    else 
    { 
     action(); 
    } 
    } 
} 
+0

-1 * BackgroundWorker가 백그라운드 스레드에서 UI를 업데이트하려고합니다. * : ** NO ** 'ProgressChanged'에서 UI를 변경합니다. 이벤트는 백그라운드 워커가 작동하는 방식입니다. @David Dansey는 File.move() 메서드가 진행 상황을보고하지 않기 때문에 ('reportProgress' 메서드 자체를 호출하지 않습니다!) 진행률이 없습니다 ... – Chris

+0

두 가지 문제를 해결하기 위해 업데이트되었습니다. 견본은 응답을 유지하고 진행보고를 통해 진행합니다. – STW

+1

내 의견을 고려하여 주셔서 감사합니다 :) 아직도 저를 방해하는 무언가가 있습니다. 내가 말하길 당신이 동의 할 때 * BackgroundWorker가 DoWork 메소드에서'label.text'를 업데이트하려고 시도하는 코드 조각에 대해 백그라운드 스레드에서 UI를 업데이트하려고 시도하고 있으므로 InvokeExtension을 사용하면 의미가 있습니다 ** 이 경우 **. 그러나 문서에서 'ProgressChanged'와'RunWorkerCompleted' 이벤트는 사용자 인터페이스 *와 통신하도록 설계되었으므로 UI ​​스레드에 있다고 생각합니다. 내 backgroundworker의 implentations에서'Invoke'를 사용한 적이 없습니다. – Chris

관련 문제