2011-06-21 27 views
5

Tôi đang chuyển dự án từ WinForms sang WPF. Khi mã của tôi dựa trên WinForms tôi đã sử dụng (this.InvokeRequired) để kiểm tra xem luồng có truy cập hay không. Bây giờ tôi sử dụng đoạn mã sau dựa trên Mainform của tôi:Sự cố với quyền truy cập giao diện người dùng từ Nhân viên nền

// this is the delegate declaration to Allow Background worker thread to write to Log Output 
    delegate void LogUpdateCallBack(String LogMessage); 

    // method to update the Log Window from the Background Thread 
    public void LogUpdate(String LogMessage) 
    { 
     Console.WriteLine("Entering"); 
     if (!Application.Current.Dispatcher.CheckAccess()) 
     { 
      Console.WriteLine("Thread doesn't have UI access"); 
      LogUpdateCallBack callback = new LogUpdateCallBack(LogUpdate); 
      Application.Current.Dispatcher.Invoke(callback, LogMessage); 
     } 
     else 
     { 
      Console.WriteLine("Thread has UI access"); 
      listBox_Output.Items.Add(LogMessage); 
      Console.WriteLine(LogMessage); 
      // listBox_Output.TopIndex = listBox_Output.Items.Count - 1; 
     } 
     Console.WriteLine("Exiting"); 
    } 

Vấn đề tôi gặp phải là Listbox không cập nhật. Không có lỗi hoặc ngoại lệ, tôi đã thử cập nhật các điều khiển giao diện người dùng khác. LogMessage đang viết vào cửa sổ Output, vì vậy tôi đang stumped.

Dưới đây là đầu ra điều khiển mẫu:

Entering 
Thread doesn't have UI access 
Entering 
Thread has UI access 
My LogMessage is output here 
Exiting 
Exiting 
Entering 
Thread doesn't have UI access 
Entering 
Thread has UI access 
My LogMessage is output here 
Exiting 
Exiting 

Tôi đã cố gắng cập nhật giao diện điều khiển khác chỉ để kiểm tra xem nó là một vấn đề với Listbox của tôi, nhưng không có may mắn.

Ngoài chuyển đổi sang CheckAccess(), thay đổi lớn khác mà tôi đã thực hiện trong mã WPF mới là căn cứ tất cả mã đang chạy trong công nhân nền trong lớp khác .. Tôi không chắc liệu điều này có thể là một phần của vấn đề?

-

@JonRaynor

tôi đã cố gắng ý tưởng của bạn:

Application.Current.Dispatcher.BeginInvoke(new LogUpdateCallBack(LogUpdate), LogMessage) 

Tuy nhiên Listbox của tôi vẫn không được cập nhật, nếu tôi ra

Console.WriteLine(listBox_Output); 

tôi xem danh sách mảng hộp phát triển:

System.Windows.Controls.ListBox Items.Count:2020 
System.Windows.Controls.ListBox Items.Count:2021 
System.Windows.Controls.ListBox Items.Count:2022 
System.Windows.Controls.ListBox Items.Count:2023 
System.Windows.Controls.ListBox Items.Count:2024 
System.Windows.Controls.ListBox Items.Count:2025 

Nhưng không có thay đổi trong biểu mẫu. Điều này rất khó hiểu!

+0

Bất kỳ liên kết dữ liệu trên Listbox ? Có một Items.Add ("test") từ sự kiện Page_Load không? –

+0

Không có DataBinding .. Tôi đang cập nhật ListBox từ các khu vực khác của mã của tôi mà không gặp khó khăn gì. Tôi cũng đã cố gắng cập nhật điều khiển giao diện người dùng khác trong trường hợp nó đã xuống đến vấn đề Listbox .. không có may mắn. – mrbencowell

+0

Một điều kỳ lạ nữa cần lưu ý .. là nếu tôi xuất listBox_Output trong Console tôi có thể thấy các mục đang được thêm vào (nó báo cáo số mục), vì vậy có vẻ như các mục của tôi đang được thêm vào, tuy nhiên giao diện người dùng không được được cập nhật. Tôi đã thử listBox_Output.InvalidateVisual(); không có hiệu lực. – mrbencowell

Trả lời

1

Cuối cùng tôi đã giải quyết vấn đề này. Vấn đề của tôi là vì tôi đã gọi phương thức LogUpdate từ cả hai chủ đề khác và một lớp khác, do đó tôi cần chuyển một tham chiếu đến biểu mẫu chính chứa hộp danh sách vào lớp này thay vì tạo một thể hiện mới của chính hình thức trong lớp trung học.

nên thay vì có tuyên bố này trong lớp học của tôi:

public MainWindow MainForm = new MainWindow(); 

tôi cần phải vượt qua một tài liệu tham khảo của form vào một phương thức trong lớp học:

public void Plot(BackgroundWorker worker, MainWindow MainForm) 
2

Tôi cũng mới bắt đầu trên WPF và phải học lại từ cách WinForms cũ. Tôi đã sử dụng BeginInvoke() và loại cú pháp này trên màn hình của tôi (biểu mẫu) ...

public delegate void WorkCompleted(); 

     /// <summary> 
     /// Marks the end of the progress 
     /// </summary> 
     private void ProgressComplete() 
     { 
      if (!this.Dispatcher.CheckAccess()) 
      { 
       this.Dispatcher.BeginInvoke(new WorkCompleted(ProgressComplete), System.Windows.Threading.DispatcherPriority.Normal, null); 
      } 
      else 
      { 
       this.buttonClose.Visibility = Visibility.Visible; 
       this.progressBarStatus.IsIndeterminate = false; 
      } 
     } 
+0

Cảm ơn bạn đã đề xuất .. Tôi sẽ thử phương pháp này và xem tôi có đi đâu không. – mrbencowell

0

Trong WPF, tất cả các điều khiển giao diện người dùng đều có nguồn gốc từ DispatcherObject. Điều đó có nghĩa là điều khiển ListBox của bạn, chính nó, một đối tượng có khả năng điều phối. Hãy thử gọi Dispatcher trên đối tượng đó thay vì dựa vào chính biểu mẫu đó. Đưa ra các tham số trên đại biểu của bạn (vì bạn có quyền truy cập vào biến LogMessage anyway) và nó sẽ giống như sau:

public void LogUpdate(string LogMessage) 
{ 
    Console.WriteLine("Entering"); 
    if (listBox_Output.Dispatcher.CheckAccess()) 
    { 
     listBox_Output.Dispatcher.Invoke(new LogUpdateCallBack(delegate 
     { 
      listBox_Output.Items.Add(LogMessage); 
     })); 
     Console.WriteLine(LogMessage); 
    } 
} 
+0

Cảm ơn gợi ý, tuy nhiên vấn đề này là do sự hiểu lầm của tôi về việc khai báo một thể hiện của MainForm trong một lớp khác, tôi cho rằng điều này sẽ cho phép tôi truy cập vào biểu mẫu chính, tuy nhiên nó chỉ tạo ra một cá thể mới. điều khiển Tôi không thấy kết quả. – mrbencowell

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