2013-04-22 59 views
5

Tôi ghét câu hỏi đầu tiên của tôi dường như đã được trả lời nhiều lần, nhưng tôi vẫn gặp khó khăn trong việc tìm cách gọi phương thức bằng cách sử dụng BackgroundWorker.Phương thức gọi từ BackgroundWorker

Tôi đang xử lý tệp văn bản rất lớn bằng cách sử dụng một loạt các lớp và phương pháp. Toàn bộ quá trình được khởi động sau khi người dùng chọn một mục dải công cụ. Tuần tự, nó đi như thế này:

  • tài khoản chọn mục công cụ dải
  • tài chọn một tập tin được xử lý thông qua một hộp thoại
  • Hành động bắt đầu

Tôi nghĩ rằng tôi có thể quấn tất cả mọi thứ vào BackgroundWorker từ thời điểm người dùng bật hộp thoại ban đầu, nhưng những gì tôi muốn làm bây giờ chỉ là đặt phương thức mà tất cả việc nâng hạng nặng được thực hiện vào trường hợp riêng của BackGroundWorker. Tôi cũng sẽ thêm một ProgressBar, nhưng tôi nghĩ rằng tôi có thể xử lý điều đó nếu tôi chỉ có thể nhận được quá trình BackgroundWorker lăn.

Từ đỉnh (. Giả sử dụng cho các mục đích dụ Phần lớn bỏ qua cho ngắn gọn):

private void ToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    string fileName = openSingleFile.FileName; 
    processFile(fileName); 
} 

static public void processFile(string fileName) 
{ 
// many vars/loops exist but not shown 

    foreach (data in bigData) 
    { 
     processItem(stringA, stringB); // <-- this method is where the expensive work is done 
     x++; 
    } 
} 

tôi đã tạo ra một thể hiện của BackgroundWorker ...:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // Things go here 
} 

... và Tôi đã thử quá nhiều thứ để liệt kê, vì vậy tôi đã quay lại phần đầu của bài trình bày ở trên.

Nếu tôi hiểu BackgroundWorker, tôi sẽ cần phải làm như sau:

  • Thay processItem (stringA, stringB) trong đoạn mã trên với một cái gì đó như:

    backgroundWorker1.RunWorkerAsync(processItem(stringA, stringB));

... và sau đó thực hiện một số loại cuộc gọi DoWork? ... và sau đó thực hiện một số loại cuộc gọi RunWorkerCompleted?

Không chắc chắn lý do tại sao bộ não của tôi bị đóng băng, nhưng tôi cảm thấy xấu hổ về lượng thời gian tôi đã dành cho việc này mà không có kết quả. Mọi sự trợ giúp sẽ rất được trân trọng. Nếu không có StackOverflow, tôi đã có thể là DOA từ lâu rồi.

FYI: Tôi đã tham chiếu các bài đăng SO, MSDN và DotNetPerls khác. Tôi chỉ thiếu một cái gì đó về mặt khái niệm, tôi cho là vậy.

+0

Đừng quên kết hợp tất cả các sự kiện của bạn. bw.DoWork + = DoWorkEventHandler mới (bw_DoWork); bw.ProgressChanged + = tiến trình mớiChangedEventHandler (bw_ProgressChanged); bw.RunWorkerCompleted + = RunWorkerCompletedEventHandler mới (bw_RunWorkerCompleted); –

+0

câu hỏi hay.helped cho tôi rất nhiều –

Trả lời

3

Thay processItem (stringA, stringB) trong đoạn mã trên với một cái gì đó giống như ...

Không, lần thứ tại sao bạn gặp rắc rối. Bạn nhất định muốn di chuyển processFile() gọi cho nhân viên. Không có lợi ích đáng kể nào từ việc chạy processItem() trong một nhân viên, ít nhất là không có trong đoạn trích bạn đã đăng. Và làm như vậy là khó khăn, nó sẽ yêu cầu bắt đầu nhiều hơn một công nhân. Một cho mỗi mục. Có rất nhiều công nhân mà mỗi công việc nhỏ nhặt đều không lành mạnh. Nếu nó thực sự là cần thiết thì bạn không muốn sử dụng BackgroundWorker, bạn sẽ muốn có một cách tiếp cận hoàn toàn khác với một số Threads tiêu thụ các gói công việc từ một hàng đợi an toàn thread. Đừng đến đó nếu bạn có thể tránh nó.

Vấn đề không nhỏ nhặt duy nhất cần giải quyết là chuyển chuỗi mà processFile() cần. May mắn là BackgroundWorker.RunWorkerAsync() có quá tải mà phải mất một đối tượng duy nhất. Vượt qua chuỗi của bạn. Lấy giá trị của nó trong trình xử lý sự kiện DoWork của bạn, truyền e.Argument trở lại một chuỗi. Do đó:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { 
     string path = (string)e.Argument; 
     processFile(path); 
    } 

    private void processToolStripMenuItem_Click(object sender, EventArgs e) { 
     backgroundWorker1.RunWorkerAsync(openSingleFile.FileName); 
     processToolStripMenuItem.Enabled = false; 
    } 

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { 
     processToolStripMenuItem.Enabled = true; 
    } 
+0

Cảm ơn bạn - Tôi đánh giá cao câu trả lời, bao gồm cả lời giải thích. Thông qua biến FileName, trên thực tế, một vấn đề mà tôi đã gặp khó khăn trong sự hiểu biết, nhưng không lưu ý trong câu hỏi của tôi. Thật khó để chọn câu trả lời, như một ví dụ khác đã cung cấp mã hoàn chỉnh cho giải pháp của tôi. Nó có vẻ vô cùng lười biếng của tôi để lựa chọn dựa trên đó, vì vậy bạn nhận được cái gật đầu cho ý kiến ​​của bạn. Trong khi tôi có mọi thứ hoạt động, tôi ước mình có thể nói rằng tôi hoàn toàn hiểu được ** tại sao ** nó hoạt động, nhưng đó là một câu hỏi khác. Trân trọng-L.I.A. – LovinItAll

1

Khởi động nhân viên nền mới là một hoạt động tốn kém. Bạn không muốn bắt đầu một cho mỗi lần lặp của một vòng lặp. Thay vào đó, hãy đặt toàn bộ vòng lặp bên trong phạm vi của một nhân viên nền duy nhất.

Khi ToolStripMenuItem_Click chạy chương trình tạo nhân viên nền của bạn, hãy processFile là những gì được thực hiện trong trình xử lý sự kiện DoWork.

Đảm bảo rằng khi thực hiện công việc đó, bạn thực sự chỉ thực hiện công việc đó, chứ không cập nhật giao diện người dùng. Bạn sẽ muốn tách logic nghiệp vụ khỏi giao diện người dùng. Nếu bạn muốn cập nhật giao diện người dùng với một số tiến trình hiện tại, hãy gọi ReportProgress và đảm bảo rằng có trình xử lý sự kiện để cập nhật giao diện người dùng đúng cách.

Nếu bạn cần cập nhật giao diện người dùng khi hoàn thành công việc thì bạn có thể làm như vậy trong trình xử lý sự kiện RunWorkerCompleted. Nếu công việc bạn đang thực hiện tạo ra một số kết quả được sử dụng để cập nhật giao diện người dùng, hãy sử dụng thuộc tính Result của nhân viên nền để chuyển nó từ phương thức DoWork đến trình xử lý hoàn thành.

+0

Cảm ơn bạn, những điểm bạn đã thực hiện được ghi nhận và giúp đóng góp cho sự hiểu biết của tôi về sinh sản một chủ đề mới và ý nghĩa của nó, nói chung. Tôi đánh giá cao việc bạn dành thời gian để cung cấp đầu vào của mình, mặc dù tôi đã chọn một câu trả lời khác trả lời đầy đủ câu hỏi (bạn đã cho tôi nhiều tín dụng hơn tôi xứng đáng lại: có thể triển khai giải pháp mà không cần thêm thông tin. , không phải bạn :) – LovinItAll

1
BackgroundWorker bgw; 

Trong sự kiện Load hoặc constructor:

bgw = new BackgroundWorker(); 
bgw.WorkerReportsProgress = true; 
//bgw.WorkerSupportsCancellation = true; 

bgw.DoWork += bgw_DoWork; 
bgw.ProgressChanged += bgw_ProgressChanged; 
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted; 

/

private void ToolStripMenuItem_Click(object sender, EventArgs e) 
    { 
     string fileName = openSingleFile.FileName; 

     bgw.RunWorkerAsync(fileName); 
    } 

    private void bgw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     string fileName = (string)e.Argument; 

     processFile(fileName); 
    } 

    private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     int Progress = e.ProgressPercentage; 

     //Update progressbar here 
    } 

    private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     //Job completed 
    } 
+1

Tôi đã chọn một câu trả lời khác vì giải thích đã cho, nhưng xin lưu ý rằng mã của bạn trực tiếp dẫn đến giải pháp của tôi hoạt động, đặc biệt là các hướng dẫn để bao gồm thông tin BackgroundWorker trong sự kiện Tải. Rất khó chọn câu trả lời - tôi thậm chí còn ngủ trên đó. W/ra mã của bạn, tôi đã dành nhiều thời gian hơn cho giải pháp của mình, nhưng w/giải thích trong câu trả lời tôi chọn, tôi sẽ chỉ sao chép và dán giải pháp vào việc hiểu thêm. Xin lưu ý rằng không chọn câu trả lời của bạn là một cuộc gọi khó khăn .... cảm ơn bạn một lần nữa. – LovinItAll

+0

Đó là tất cả tốt, vui vì tôi có thể giúp – kschieck

Các vấn đề liên quan