2009-09-24 7 views
15

Tôi gặp sự cố như sau:C# Winform ProgressBar và BackgroundWorker

Tôi có Biểu mẫu có tên MainForm. Tôi có một hoạt động dài được thực hiện trên mẫu đơn này.

Trong khi hoạt động dài này đang diễn ra, tôi cần hiển thị một tệp khác từ tên ProgressForm trên đầu trang của MainForm.

ProgressForm chứa thanh tiến trình. Mà cần phải được cập nhật trong khi hoạt động lâu dài đang diễn ra.

Sau khi hoàn thành thao tác dài, ProgressForm sẽ tự động được đóng lại.

Tôi đã viết một số mã như sau:

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 

namespace ClassLibrary 
{ 
    public class MyClass 
    { 
     public static string LongOperation() 
     { 
      Thread.Sleep(new TimeSpan(0,0,30)); 

      return "HelloWorld"; 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class ProgressForm : Form 
    { 
     public ProgressForm() 
     { 
      InitializeComponent(); 
     } 

     public ProgressBar ProgressBar 
     { 
      get { return this.progressBar1; } 
      set { this.progressBar1 = value; } 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

using ClassLibrary; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class MainForm : Form 
    { 
     ProgressForm f = new ProgressForm(); 

     public MainForm() 
     { 
      InitializeComponent(); 
     } 

     int count = 0; 
     private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      if (f != null) 
      { 
       f.ProgressBar.Value = e.ProgressPercentage; 
      } 

      ++count; 
     } 

     private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if (e.Cancelled) 
      { 
       MessageBox.Show("The task has been cancelled"); 
      } 
      else if (e.Error != null) 
      {     
       MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString()); 
      } 
      else 
      { 
       MessageBox.Show("The task has been completed. Results: " + e.Result.ToString()); 
      } 
     } 


     private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
     { 
      if (f == null) 
      { 
       f = new ProgressForm(); 
      } 

      f.ShowDialog(); 

      //backgroundWorker1.ReportProgress(100); 

      MyClass.LongOperation(); 

      f.Close(); 
     } 

     private void btnStart_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.RunWorkerAsync(); 
     } 

     private void btnCancel_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.CancelAsync(); 

      this.Close(); 
     } 
    } 
} 

Tôi không tìm cách để cập nhật các ProgressBar.

Tôi nên đặt backgroundWorker1.ReportProgress() ở đâu và tôi nên gọi điều này như thế nào?

Tôi không được thực hiện bất kỳ thay đổi nào trong MyClass. Coz, tôi không biết điều gì sẽ xảy ra hoặc mất bao lâu để hoàn thành hoạt động trong lớp ứng dụng của tôi.

Có ai có thể giúp tôi không?

Trả lời

12

Một vấn đề là bạn đang ngủ trong 30 giây. Thông thường bạn sẽ gọi số ReportProgress tại các điểm khác nhau trong tác vụ dài hạn của mình. Vì vậy, để chứng minh điều này, bạn có thể muốn thay đổi mã của bạn để ngủ trong 1 giây, nhưng 30 lần - gọi ReportProgress mỗi khi nó kết thúc một giấc ngủ.

Một vấn đề khác là bạn đang hiển thị ProgressFormcủa mình từ chuỗi nền. Bạn nên bắt đầu nó trong chuỗi giao diện người dùng UI, nhưng móc sự kiện ProgressChanged của nhân viên nền đó. Sau đó, khi nhân viên nền báo cáo tiến độ, biểu mẫu tiến trình sẽ được cập nhật.

+0

Tôi không được thực hiện bất kỳ thay đổi nào trong MyClass. Coz, tôi không biết điều gì sẽ xảy ra trong lớp ứng dụng của tôi. – anonymous

+6

Sau đó, bạn không thể báo cáo chính xác tiến độ. Tôi có nghĩa là bạn có thể thêm một bộ đếm thời gian vào 'ProgressForm' để chỉ tăng thanh tiến trình mỗi giây, nhưng điều đó sẽ chỉ cung cấp một ảo tưởng. Nếu bạn không có cách nào để tìm ra tiến trình * thực tế *, thì thanh tiến trình hữu ích như thế nào? –

2

ReportProgress là phương pháp mà bạn sẽ phải gọi trong phương thức 'đang hoạt động' của mình. Phương pháp này sẽ tăng sự kiện 'ProgressChanged'.

Trong biểu mẫu của mình, bạn có thể đính kèm một eventhandler vào sự kiện ProgressChanged. Bên trong eventhandler đó, bạn có thể thay đổi vị trí của thanh tiến trình. Bạn cũng có thể đính kèm một eventhandler vào sự kiện RunWorkerCompleted, và bên trong eventhandler đó, bạn có thể đóng biểu mẫu chứa thanh tiến trình.

+0

Đây là giải pháp chung tôi đoán. Plz đọc lại vấn đề. – anonymous

2

Cần lưu ý bạn cần phải thiết lập

backgroundWorker1.WorkerReportsProgress = true; 

nếu bạn muốn người lao động nền để nâng cao sự kiện ProgressChanged và

backgroundWorker1.WorkerSupportsCancellation = true; 

nếu bạn muốn để có thể hủy bỏ các sợi nhân.

Như những người khác đã nói, hãy chạy f.ShowDialog() trong chuỗi giao diện người dùng của bạn và sử dụng ProgressChanged để cập nhật ProgressWindow.

Để lấy ProgressForm tự đóng, trong backgroundWorker1_RunWorkerCompleted, hãy gọi f.Gần(); Điều này có nghĩa là hoạt động lâu dài đã hoàn thành và chúng tôi có thể đóng cửa sổ.

+0

Lợi ích của việc gọi ProgressWindow từ chuỗi giao diện người dùng là gì? – anonymous

0

Điều cần thiết ở đây là không chuyển toàn bộ biểu mẫu chính cho lớp học, mà chỉ đơn giản là trường hợp của BackgroundWorker của bạn! Bạn cần phải đúc người gửi như công nhân Bối cảnh như vậy:

private void bgWorker_DoWork(object sender DoWorkEventArgs e) 
{ 
    // Get the BackgroundWorker that raised this event 
    BackgroundWorker worker = sender as BackgroundWorker; 

    // And now you just send worker to whatever class you need like so: 
    bgArgs args = e.Argument as bgArgs; 
    MyClass objMyClass = new MyClass(); 

    MyClass.MyMethod(strValue, args.Option, worker); 

    // Do something based on return value. 
} 

Và sau đó trong MyClass.MyMethod() của bạn, bạn sẽ làm các tính toán tiến độ và chỉ đơn giản là nâng cao sự kiện worker.ReportProgress(int percentage) để cập nhật các thanh tiến trình hoặc không có điều gì vào mẫu giao diện người dùng chính của bạn!

Điều này sẽ hoạt động hoàn hảo!

Kiểm tra bài viết MSDN này để biết thêm chi tiết, xem ví dụ Fibonacci của chúng, đó là những gì chúng làm từ CalculateFibonacci là lớp tùy chỉnh gửi bản cập nhật cho giao diện người dùng của biểu mẫu chính.

Xem MSDN BackgroundWorker Class để biết thêm chi tiết.