2010-06-23 10 views
9

Trong một ứng dụng WPF, tôi đang sử dụng một BackgroundWorker để định kỳ kiểm tra tình trạng trên máy chủ. Trong khi đó hoạt động tốt, tôi muốn bật một MessageBox notifing người sử dụng nếu một cái gì đó không thành công trong quá trình kiểm tra.Popping một MessageBox cho ứng dụng chính với Backgroundworker trong WPF

Dưới đây là những gì tôi có:

public static void StartWorker() 
{ 
    worker = new BackgroundWorker(); 

    worker.DoWork += DoSomeWork; 
    worker.RunWorkerAsync(); 
} 

private static void DoSomeWork(object sender, DoWorkEventArgs e) 
{ 
    while (!worker.CancellationPending) 
    { 
     Thread.Sleep(5000); 

     var isOkay = CheckCondition(); 

     if(!isOkay) 
      MessageBox.Show("I should block the main window");     
    } 
} 

Nhưng MessageBox này không chặn cửa sổ chính. Tôi vẫn có thể bấm vào ứng dụng WPF của tôi và thay đổi bất cứ điều gì tôi thích với MessageBox xung quanh.

Làm cách nào để giải quyết vấn đề này? Cảm ơn,


EDIT:

Để tham khảo, đây là những gì tôi đã kết thúc thực hiện:

public static void StartWorker() 
{ 
    worker = new BackgroundWorker(); 

    worker.DoWork += DoSomeWork; 
    worker.ProgressChanged += ShowWarning; 
    worker.RunWorkerAsync(); 
} 

private static void DoSomeWork(object sender, DoWorkEventArgs e) 
{ 
    while (!worker.CancellationPending) 
    { 
     Thread.Sleep(5000); 

     var isOkay = CheckCondition(); 

     if(!isOkay) 
      worker.ReportProgress(1);     
    } 
} 

private static void ShowWarning(object sender, ProgressChangedEventArgs e) 
{ 
    MessageBox.Show("I block the main window"); 
} 

Trả lời

6

Gọi ReportProgress và vượt qua this để MessageBox.Show.

10

Nó không chỉ không chặn cửa sổ chính, nó cũng rất có khả năng biến mất đằng sau nó. Đó là hậu quả trực tiếp của nó chạy trên một chủ đề khác. Khi bạn không chỉ định một chủ sở hữu cho hộp thư thì nó sẽ tìm kiếm một với hàm GetActiveWindow() API. Nó chỉ xem xét các cửa sổ sử dụng cùng một hàng đợi tin nhắn. Thuộc tính cụ thể theo chủ đề nào. Mất một hộp tin nhắn là khá khó khăn để đối phó với tất nhiên.

Tương tự, MessageBox chỉ vô hiệu hóa các cửa sổ thuộc cùng một hàng đợi thư. Và do đó sẽ không chặn các cửa sổ được tạo bởi chủ đề chính của bạn.

Khắc phục sự cố của bạn bằng cách cho phép chuỗi giao diện người dùng hiển thị hộp tin nhắn. Sử dụng Dispatcher.Invoke hoặc tận dụng các sự kiện ReportProgress hoặc RunWorkerCompleted. Có vẻ như các sự kiện không phù hợp ở đây.

+0

Cảm ơn bạn, tôi đã có một cảm giác rằng đây là liên quan đến chủ đề, nhưng tôi không có ý tưởng làm thế nào để giải quyết nó. Sử dụng "ReportProgess" hoặc "RunWorkerCompleted" không trực quan, nhưng việc đọc các giải thích không tạo ra nhiều ý nghĩa hơn. –

3

Thay

MessageBox.Show("I should block the main window"); 

với

this.Invoke((Func<DialogResult>)(() => MessageBox.Show("I should block the main window"))); 

rằng sẽ làm cho hộp thông báo để được vào các chủ đề chính và sẽ chặn tất cả các truy cập vào giao diện người dùng cho đến khi nó được một câu trả lời. Như một tiền thưởng thêm this.Invoke sẽ trả về một đối tượng có thể được đưa vào DialogResult.

+0

Tôi cũng muốn thử giải pháp này, nhưng tôi không thể biên dịch nó. Tôi đang gọi nó từ một lớp bình thường (không phải là một điều khiển) và nó không có Invoke trên nó. Tôi cũng đã thử "Dispatcher.CurrentDispatcher.Invoke()" nhưng nó không lấy Func được đề xuất –

+0

Tôi cho rằng điều này đã được gọi từ biểu mẫu. để có thể thực hiện phương pháp này, bạn sẽ cần phải chuyển lớp tham chiếu đến biểu mẫu gốc và sử dụng _ParentForm.Invoke (...), có thể có một cách khác để làm điều đó nhưng tôi không biết bất kỳ phần nào ở đầu đầu của tôi. –

+0

Điều này thậm chí không biên dịch trên biểu mẫu –

2

Như Stephen và Hans đã nói, hãy sử dụng sự kiện ReportProgress và chuyển dữ liệu đến chuỗi giao diện người dùng. Điều này đặc biệt quan trọng nếu bạn muốn làm bất cứ điều gì khác tha MessageBox (cho isntance, cập nhật một điều khiển) bởi vì các chủ đề nền không thể làm điều này trực tiếp. Bạn sẽ nhận được một ngoại lệ cross-thread. Vì vậy, bất cứ điều gì bạn cần làm (cập nhật thanh tiến trình, thông điệp tường trình vào giao diện người dùng, vv), chuyển dữ liệu đến chuỗi giao diện người dùng, cho biết chuỗi giao diện người dùng cần phải làm gì, nhưng để cho chuỗi giao diện người dùng làm điều đó.

1

tôi sửa đổi nó như thế này và làm việc tốt cho tôi

return Application.Current.Dispatcher.Invoke(() => MessageBox.Show(messageBoxText, caption, button, icon)); 
+1

Shoudl là một bình luận về câu trả lời theo. – user3595247