2012-03-18 28 views
5

tôi sử dụng một BackgroundWorker và làm điều này:Tại sao tôi không nhận được "hoạt động Chữ thập sợi không hợp lệ" lỗi

private void loadNewAsyncToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    this.Text = "RunWorkerAsync()"; 
    backgroundWorkerLoading.RunWorkerAsync(); 
} 
private void backgroundWorkerLoading_DoWork(object sender, DoWorkEventArgs e) 
{ 
    UnsafeThreadMethod("hello"); 
    EvenUnsaferThreadMethod(); 
} 

Và bây giờ là hai phương pháp.

private void UnsafeThreadMethod(string text) 
{ 
    toolStripLabelRssFeedData.Text = text; 
} 

private void EvenUnsaferThreadMethod() 
{ 
    panelLoading.Visible = true; 
} 

Tôi không hiểu tại sao UnsafeThreadMethod không ném ngoại lệ sau nhưng EvenUnsaferThreadMethod làm.

Hoạt động trên luồng không hợp lệ: Kiểm soát 'panelLoading' được truy cập từ một chủ đề không phải là> chuỗi được tạo trên đó.

Theo thông báo là vì toolStripLabelRssFeedData được tạo trên cùng một chuỗi nhưng không phải.

Tôi nghĩ rằng tôi không thể gọi các điều khiển được tạo bởi chuỗi chính và phải sử dụng sự kiện ProgressChanged. Chuyện gì vậy?

Và tôi có câu hỏi thứ hai. Lợi thế của việc làm như thế này khi tôi có thể sử dụng ProgressChanged là gì? Tôi nên làm gì?

private void EvenUnsaferThreadMethod() 
{ 
    if (panelLoading.InvokeRequired) 
    { 
     panelLoading.Invoke(new MethodInvoker(() => { EvenUnsaferThreadMethod(); })); 
    } 
    else 
    { 
     panelLoading.Visible = true; 
    } 
} 

Trả lời

5

Để câu hỏi đầu tiên:

  • ngoại trừ cross-thread cố ý ném vào chế độ gỡ lỗi. Điều này có nghĩa là kiểm tra mã (có điều kiện) trên InvokeRequired được tích hợp vào hầu hết các điều khiển GUI. Giống như bảng điều khiển.

  • Rõ ràng ToolstripLabel không thực hiện kiểm tra này. Vì nó không lấy được từ Điều khiển có thể bởi vì nó nằm ngoài phạm vi của mạng lưới an toàn này.

Kể từ khi từ chối trách nhiệm chuẩn "Bất kỳ thành viên dụ không đảm bảo được chủ đề an toàn" áp dụng cho ToolstripLabel tôi sẽ chỉ đi với logic InvokeRequired bình thường khi thiết lập các văn bản.

+1

Tôi nghĩ câu trả lời này giải quyết những gì OP hỏi là lý do tại sao cuộc gọi không an toàn rõ ràng không phải là một ngoại lệ. Tất cả đều xoay quanh thực tế rằng ToolStripLabel không lấy được từ Control và không kiểm tra sự an toàn của luồng. Nó chỉ xảy ra để làm việc, nhưng như người khác đã chỉ ra, bạn không thể tin vào điều đó để ở lại sự thật mãi mãi. –

0

Ưu điểm của thứ hai sự lựa chọn của bạn là nó làm việc :)

Tất cả các yếu tố giao diện người dùng được tạo ra trên thread UI chính và, những gì là quan trọng hơn từ góc độ câu hỏi này, là có thể được chỉ được gắn trong chủ đề đó.

Đây là lý do tại sao trường hợp đầu tiên của bạn không thành công và đó là lý do trường hợp giây thứ hai của bạn sẽ hoạt động. Invoke()... sẽ chuyển hướng cuộc gọi merhod cần thiết đến chuỗi giao diện người dùng chính.

Hy vọng điều này sẽ hữu ích.

+0

Cảm ơn câu trả lời của bạn. Bạn nói 'UnsafeThreadMethod' không nên hoạt động vì giao diện người dùng trên một chủ đề khác nhưng bằng cách nào đó và đó là điều tôi không hiểu. Ngoài ra, câu hỏi cuối cùng là nếu nó là tốt hơn để sử dụng các công cụ gọi hoặc 'ProgressChanged' và' RunWorkerCompleted' (mà sẽ làm việc vì họ đang trở lại trên thread bên phải). – pelz

+0

Đó là trường hợp đầu tiên * đôi khi * hoạt động có vẻ kỳ lạ đối với tôi. Điều gì về trường hợp thứ hai: xem xét rằng trong phương pháp của bạn, bạn truy cập vào phần tử giao diện người dùng, bạn * phải * sử dụng 'Invoke' để chuyển hướng cuộc gọi đến chuỗi giao diện người dùng. Nó không thể hoạt động theo cách khác. – Tigran

+0

Bằng cách nào đó nó bcause hành vi không được xác định. Nó có thể phá vỡ theo ý muốn, tại gói dịch vụ, tại hotfix. – TomTom

3

Đối với câu hỏi đầu tiên của bạn, tôi không hoàn toàn chắc chắn, nhưng đánh giá trực tuyến dường như cho thấy đôi khi điều này sẽ không ném ngoại lệ, nhưng nó sẽ không cập nhật nhãn. Đó có phải là trường hợp ở đây không? Nhãn của bạn có được cập nhật cùng với không có ngoại lệ không?

Tuy nhiên, tôi có thể trả lời câu hỏi thứ hai của bạn ngay bây giờ. Sự kiện ProgressChanged có nghĩa là cho chính xác những gì nó âm thanh như thế nào. Nó được cho là được gọi để cho thread UI biết trạng thái của backgroundworker sao cho nó có thể cập nhật chính nó một cách thích hợp. Chuỗi gọi ban đầu (Giao diện người dùng trong trường hợp này) là chuỗi được sử dụng cho số ProgressChanged, vì vậy khi cập nhật nó không cần gọi số Invoke. Nhưng, điều này thực sự chỉ nên được thực hiện để hiển thị tiến trình của một nhân viên nền.

Bây giờ, nếu đó không phải là bản cập nhật mà bạn đang cố gắng chuyển sang phương thức gọi điện, thì tôi khuyên bạn chỉ nên chuyển dữ liệu trả về của mình trở lại thông qua sự kiện RunWorkerCompleted. Thao tác này chuyển tất cả dữ liệu cuối cùng của bạn trở lại luồng ban đầu (Giao diện người dùng) để có thể cập nhật giao diện người dùng mà không cần bất kỳ yêu cầu nào cho số Invoke.

Vì vậy, hãy gọi điện tới số Invoke của bạn. Tuy nhiên, hiểu được từng sự kiện nào khác có thể giúp bạn hiểu lý do tại sao sử dụng theo cách này sang cách khác.Có lẽ sự kiện ProgressChanged phù hợp hơn? Nó cũng có thể làm suy giảm mã của bạn khi có các cuộc gọi không cần thiết.

Update để q đầu tiên

tôi vẫn không thể tìm thấy bất cứ điều gì về toolstrip không cần các invoke. Trong thực tế, tôi đang tìm kiếm ngược lại bằng cách sử dụng tìm kiếm google như "toolstriplabel no cross thread exception" hoặc "toolstriplabel invoke", v.v. Tuy nhiên, như henk đã đề cập, toolstriplabel không kế thừa từ điều khiển để giải thích tại sao không yêu cầu được gọi. Tuy nhiên, đề xuất của tôi là giả định rằng nó sẽ hoạt động giống như bất kỳ điều khiển giao diện người dùng nào khác và đảm bảo rằng nó được cập nhật trên chuỗi giao diện người dùng để an toàn. không dựa vào quirks. an toàn hơn xin lỗi, bạn không bao giờ biết nếu mọi thứ như thế này có thể thay đổi, đặc biệt là vì nó là một cách logic một mục UI với hầu hết ..,

+0

Cảm ơn bạn đã trả lời. Về câu hỏi đầu tiên: có, nó sẽ cập nhật nhãn tốt. Câu trả lời của bạn cho câu hỏi thứ hai của tôi đã xóa hết mọi thứ. Tôi nghĩ rằng trong trường hợp của tôi 'RunWorkerCompleted' là con đường để đi. – pelz

+0

Rất vui được giúp đỡ. Tôi đã cập nhật câu trả lời để đưa ra ý kiến ​​của mình trên nhãn sau khi nghiên cứu thêm –

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