2012-12-05 46 views
5

Tôi đang viết một lớp thực hiện một hoạt động nhất định trong thư viện. Nhưng các hoạt động là tẻ nhạt, và tôi muốn để có thể tìm ra sự tiến bộ của phương pháp bên trong lớp đó để tôi có thể sử dụng nó trong một ứng dụng WinForms để báo cáo sự tiến bộ.Viết phương pháp báo cáo tiến độ

Tôi đang lên kế hoạch chạy lớp của mình trên một chuỗi khác trong ứng dụng WinForms của mình và tôi muốn lớp được tách khỏi các mối quan tâm của ứng dụng WinForms và tôi không muốn liên kết nó với bất kỳ điều gì khác ngoài nó có.

Cách tốt nhất để triển khai cơ chế báo cáo tiến trình trong lớp thư viện là gì?

Một ý tưởng hay là bằng cách nào đó có một biến tiến bộ trong lớp và thêm trình xử lý sự kiện vào nó trong ứng dụng WinForms của tôi? Và nếu nó là, làm thế nào tôi có thể làm điều đó?

Chỉnh sửa: Tôi đã sử dụng lớp BackgroundWorker trước đây, nhưng vấn đề của tôi là tôi không muốn lớp thư viện của mình quan tâm đến bất kỳ hoạt động đa luồng nào. Vì vậy, tôi không muốn gọi ReportProgress trong lớp thư viện, tôi muốn (có thể) có một biến trong lớp có chứa tiến trình hiện tại và tôi muốn chuỗi giao diện người dùng bằng cách nào đó "đăng ký" với nó. Tôi không biết nếu đó là một cách tốt để thiết kế nó mặc dù.

+0

Có nhiều cách tiếp cận khác nhau nhưng mã hiện tại của bạn trông như thế nào ..? nó sẽ giúp nếu bạn sẽ cung cấp những gì bạn đã thử cho đến nay .. – MethodMan

+0

Tôi không có nhiều mã vào lúc này. Tôi muốn tìm hiểu cách tiến hành trước khi viết lớp. Tôi thực sự đánh giá cao nếu bạn có thể chỉ cho tôi một số cách tiếp cận nổi tiếng cho vấn đề này. – hattenn

Trả lời

4

Nhìn vào lớp BackgroundWorker. Nó hỗ trợ marshaling tự động trên các luồng cho báo cáo tiến độ, và nó có một mô hình sự kiện rất đơn giản cho kiểu hỗ trợ này.

Sửa: Do vị trí của bạn về việc sử dụng BackgroundWorker trực tiếp, những gì bạn có thể làm là tạo một wrapper đơn giản:

// Error checking elided for expository purposes. 
public interface IProgressReporter 
{ 
    void ReportProgress(int progress, object status); 
} 

public class BackgroundWorkerProgressReporter : IProgressReporter 
{ 
    private BackgroundWorker _worker; 
    public BackgroundWorkerProgressReporter(BackgroundWorker worker) 
    { 
     _worker = worker; 
    } 

    public void ReportProgress(int progress, object status) 
    { 
     _worker.ReportProgress(progress, status); 
    } 
} 

Sau đó, thay đổi các nhà xây dựng (hoặc thêm một tài sản) của lớp mà bạn muốn để báo cáo tiến trình chấp nhận một IProgressReporter. Đây là một dạng tiêm phụ thuộc, và nên cho phép đối tượng của bạn báo cáo tiến độ trong khi cũng tránh các phụ thuộc cụ thể trên các thư viện luồng.

+0

Vui lòng xem bản chỉnh sửa của tôi. – hattenn

+0

Tôi đã thêm một ví dụ về mã mà bạn có thể sử dụng. – Rob

1

Ở đây bạn có thể làm 2 cách khác nhau tôi sẽ gửi cả hai lựa chọn dưới đây để giúp điểm bạn đi đúng hướng

Bạn nên được làm điều này trên thread khác, và sau đó cập nhật thread UI của bạn từ chủ đề đó. Bạn đang chặn xử lý tiếp theo bằng cách thực hiện tác vụ này trên chuỗi giao diện người dùng.

Nếu bạn không thể di chuyển mã này vào thread UI, sau đó bạn có thể luôn luôn gọi Application.DoEvents, nhưng tôi mạnh mẽđề nghị bạn khám phá các tùy chọn đầu tiên:

Second Alternative bạn có thể làm một cái gì đó như thế này:

Bạn sẽ cần phải nhận được dữ liệu của bạn từ một thread để người kia. Điều này có thể được thực hiện theo một vài cách ...

Đầu tiên, chuỗi "nền" của bạn có thể cập nhật một số loại biến chuỗi "CurrentStatus" mà nó thay đổi khi nó đi cùng. Sau đó bạn có thể đặt một bộ đếm thời gian trên biểu mẫu của bạn sau đó sẽ lấy biến CurrentStatus và cập nhật nhãn với nó.

Thứ hai, bạn có thể đơn giản gọi thao tác từ chuỗi nền tới chuỗi giao diện người dùng với đại biểu bằng thuộc tính InvokeRequired của điều khiển nhãn. Vì vậy, ví dụ ...

private delegate void UpdateStatusDelegate(string status); 
private void UpdateStatus(string status) 
{ 
    if (this.label1.InvokeRequired) 
    { 
     this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status }); 
     return; 
    } 

    this.label1.Text = status; 
} 

Bạn có thể gọi đó là UpdateStatus() phương pháp từ bất kỳ thread (UI hoặc nền) và nó sẽ phát hiện hay không nó cần phải gọi các hoạt động trên thread UI chính (và nếu vì vậy, hiện nó).

Edit: Để thực sự thiết lập các chủ đề, bạn có thể làm như vậy như thế này:

private void StartProcessing() 
    { 
     System.Threading.Thread procThread = new System.Threading.Thread(this.Process); 

     procThread.Start(); 
    } 

    private void Process() // this is the actual method of the thread 
    { 
     foreach (System.IO.FileInfo f in dir.GetFiles("*.txt")) 
     { 
      // Do processing 
      // Show progress bar 
      // Update Label on Form, "f.Name is done processing, now processing..." 
      UpdateStatus("Processing " + f.Name + "...");     
     } 
    } 

Sau đó, khi người dùng nhấp chuột vào nút "GO" bạn sẽ chỉ cần gọi StartProcessing().

+0

Vui lòng xem bản chỉnh sửa của tôi. – hattenn