2010-01-05 41 views
5

Tôi đã tìm kiếm trên diễn đàn nhưng không có câu hỏi nào phù hợp với vấn đề của tôi ...Tại sao BackgroundWorker_RunWorkerCompleted không cập nhật GUI?

Tôi sử dụng một BackgroundWorker để xử lý thao tác tốn thời gian. Sau khi hoàn thành thao tác này, nút sẽ được đặt thành bật để người dùng có thể thực hiện một thao tác khác.

Tôi đang sử dụng WPF và tôi đang theo mẫu MVVM, vì vậy tôi không có quyền truy cập trực tiếp vào nút này. Tôi phải gọi một phương thức trong trình xử lý sự kiện BackgroundWorker_RunWorkerCompleted đặt thuộc tính, biểu diễn các nút được bật trạng thái, thành true.

Tất cả đều hoạt động tốt ngoại trừ một điều: Nút chỉ được vẽ lại sau tôi, ví dụ: nhấp vào cửa sổ (hoặc phóng to cửa sổ, ...). Thats rất khó chịu và đưa tôi cả ngày để thoát khỏi hành vi này nhưng tôi không thể tìm thấy một giải pháp ...

Các xử lý sự kiện BackgroundWorker_RunWorkerCompleted trông như thế này:

void fileLoadBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { 
     SetButtonToEnabled(); } 

Có ai bất kỳ ý tưởng như thế nào để khắc phục vấn đề này?

Edit:

Các nút được ràng buộc với một lệnh:

<Button Name="btnLoadTargetFile" Command="{Binding Path=LoadTargetCommand}" .../> 

Lệnh này là một RelayCommand như Smith nói trong blog của mình (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx) và trông như thế này:

public RelayCommand LoadTargetCommand 
    { 
     get 
     { 
      if (loadTargetCommand == null) 
      { 
       loadTargetCommand = new RelayCommand(param => this.OnRequestLoadFile(BusinessLogic.CustomTypes.TreeType.Target), param => this.CanLoadTarget); 
      } 
      return loadTargetCommand; 
     } 
     set { loadTargetCommand = value; } 
    } 

this.CanLoadTarget được đặt thành true bởi SetButtonToEnabled(); phương pháp

Chỉnh sửa 2:

đoạn mã sau 'làm việc':

fileLoadBackgroundWorker.RunWorkerAsync(argumentList); 
while(fileLoadBackgroundWorker.IsBusy) 
    System.Windows.Forms.Application.DoEvents(); 
SetButtonToEnabled(); 

nhưng đó là một số loại mã thực sự nguy hiểm và xấu xí ...

+0

Khi bạn đặt thuộc tính thành true, bạn tăng sự kiện 'PropertyChanged' (tức là. Viewmodel của bạn có triển khai' INotifyPropertyChanged' đúng không?) –

+0

Nếu tôi gọi phương thức đó sau khi fileLoadBackgroundWorker.RunWorkerAsync() mọi thứ hoạt động tốt, vì vậy tôi không nghĩ đó là vấn đề ?! – lakai

+0

Chỉ vì tò mò, bạn có đang sử dụng bất kỳ sửa đổi WMI nào cho hình dạng hoặc đường viền của biểu mẫu (màu đường viền, v.v ...) không? –

Trả lời

2

Mặc dù đây doesnt giải thích vấn đề của bạn, bạn có thể cố gắng thêm

System.Windows.Forms.Application.DoEvents(); 

hoặc

Dispatcher.Invoke(new Action(delegate { }), DispatcherPriority.Background); 

đến cuối cuộc gọi chức năng SetButtonToEnabled của bạn (sau khi bạn thiết lập các nút Enabled là true). Có vẻ như backgroundworker đang gọi sự kiện Complete, nhưng GUI không làm mới.

Here là một ví dụ hoàn chỉnh bằng cách sử dụng Backgroundworker trong WPF. Bạn có thể muốn nhìn vào nó và chắc chắn rằng các công cụ của bạn trông giống nhau.

Bạn cũng có thể xem Asynchronous Threading with Background Worker Object. Đây là ví dụ hay về việc sử dụng Trình điều phối và Backgroundworker

WPF Threading Model là một nguồn tuyệt vời khác để kiểm tra.

+0

cảm ơn nhận xét của bạn! mã của tôi trông giống như ví dụ ngoại trừ việc tôi không có quyền truy cập trực tiếp vào các nút vì mẫu MVVM tôi sử dụng – lakai

+0

Bạn có thể đăng mã cho SetButtonToEnabled không. Tôi không nghĩ rằng đó là một vấn đề với backgroundworker, kể từ khi bạn đề cập rằng hoàn thành không nhận được gọi là. Nó có thể là một cái gì đó bạn đang làm trên các chủ đề chính. Bạn đang làm gì trong khi quá trình đang chạy trong nền? – SwDevMan81

+1

Bạn có thể muốn kiểm tra InvalidateRequerySuggested: http://msdn.microsoft.com/en-us/library/system.windows.input.commandmanager.invalidaterequerysuggested.aspx Thử thêm phần này vào cuối SetButtonToEnabled – SwDevMan81

1

Vấn đề của bạn có lẽ không có gì để làm với BackgroundWorker. Nếu bạn gọi phương thức SetButtonToEnabled trực tiếp từ chuỗi chính, bạn có thể sẽ thấy cùng một hành vi. Thay thế cuộc gọi đến RunWorkerAsync bằng một đến SetButtonToEnabled để kiểm tra điều này.

Một vài người nhận xét cho rằng bạn xem xét việc thực hiện INotifyPropertyChanged điều này nghe giống như lời khuyên tốt.

+0

cảm ơn câu trả lời của bạn! Nếu tôi gọi SetButtonToEnabled trong chủ đề chính, mọi thứ hoạt động tốt ... – lakai

+0

Bạn có thể xác nhận rằng sự kiện RunWorkerCompleted đang được nâng lên không? Có một breakpoint mà bạn đặt ở đó có được hit? –

+0

vâng, điểm ngắt được nhấn – lakai

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