2009-10-29 17 views
60

Gần đây tôi đã bắt đầu lập trình trong WPF và gặp phải vấn đề sau. Tôi không hiểu cách sử dụng phương thức Dispatcher.Invoke(). Tôi có kinh nghiệm về luồng và tôi đã thực hiện một vài chương trình Windows Forms đơn giản, nơi tôi vừa sử dụngThay đổi điều khiển WPF từ một chủ đề không chính bằng Dispatcher.Invoke

Control.CheckForIllegalCrossThreadCalls = false; 

Vâng tôi biết đó là khá đơn giản nhưng đây là những ứng dụng giám sát đơn giản. Thực tế là bây giờ tôi đang làm một ứng dụng WPF lấy dữ liệu trong nền, tôi bắt đầu một chủ đề mới để thực hiện cuộc gọi để lấy dữ liệu (từ một máy chủ web), bây giờ tôi muốn hiển thị nó trên WPF của tôi hình thức. Vấn đề là, tôi không thể thiết lập bất kỳ điều khiển từ chủ đề này. Thậm chí không có nhãn hay gì cả. Vấn đề đó được giải quyết như thế nào?

trả lời bình luận:
@Jalfp:
Vì vậy, tôi sử dụng phương pháp Dispatcher này trong 'lốp mới' khi tôi nhận được dữ liệu? Hoặc tôi nên làm cho một nhân viên nền lấy dữ liệu, đưa nó vào một lĩnh vực và bắt đầu một chủ đề mới cho đến khi trường này được lấp đầy và gọi điều phối viên để hiển thị dữ liệu đã truy xuất vào các điều khiển?

Trả lời

145

Điều đầu tiên là phải hiểu rằng, Bộ điều phối không được thiết kế để chạy hoạt động chặn dài (chẳng hạn như truy xuất dữ liệu từ Máy chủ Web ...). Bạn có thể sử dụng Dispatcher khi bạn muốn chạy một hoạt động sẽ được thực hiện trên luồng giao diện người dùng (chẳng hạn như cập nhật giá trị của thanh tiến trình).

Điều bạn có thể làm là truy xuất dữ liệu của mình trong một nhân viên nền và sử dụng phương pháp ReportProgress để truyền bá các thay đổi trong chuỗi giao diện người dùng.

Nếu bạn thực sự cần phải sử dụng Dispatcher trực tiếp, nó khá đơn giản:

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Background, 
    new Action(() => this.progressBar.Value = 50)); 
+19

Bạn có thể thoát khỏi những 'hành động mới (' một phần, và chỉ cần sử dụng một biểu thức lambda: DispatcherPriority.Background,() => this.progressBar.Value = 50 – jrista

+0

Ừ không biết tại sao tôi đặt một Hành động ở đây: p – japf

+0

Vì vậy, tôi sử dụng phương pháp này Dispatcher trong 'mới tread' khi tôi nhận được dữ liệu? Hoặc tôi nên làm cho một nhân viên nền lấy dữ liệu, đặt nó vào một lĩnh vực và bắt đầu một thread mới chờ đợi cho đến khi lĩnh vực này là điền và gọi điều phối để hiển thị dữ liệu đã truy xuất vào các điều khiển? –

19

japf có trả lời nó một cách chính xác. Chỉ trong trường hợp nếu bạn đang xem các hành động đa dòng, bạn có thể viết như dưới đây.

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Background, 
    new Action(() => { 
    this.progressBar.Value = 50; 
    })); 

Thông tin dành cho những người dùng khác muốn biết về hiệu suất:

Nếu CẦN mã của bạn phải được viết cho hiệu suất cao, bạn có thể kiểm tra đầu tiên nếu invoke được yêu cầu bằng cách sử dụng CheckAccess cờ.

if(Application.Current.Dispatcher.CheckAccess()) 
{ 
    this.progressBar.Value = 50; 
} 
else 
{ 
    Application.Current.Dispatcher.BeginInvoke(
     DispatcherPriority.Background, 
     new Action(() => { 
     this.progressBar.Value = 50; 
     })); 
} 

Lưu ý rằng phương thức CheckAccess() bị ẩn khỏi Visual Studio 2015 nên chỉ cần viết nó mà không mong muốn hiển thị nó. Lưu ý rằng CheckAccess có phí trên hiệu suất (trên đầu trong vài nano giây). Nó chỉ tốt hơn khi bạn muốn tiết kiệm rằng micro giây cần thiết để thực hiện 'invoke' bằng mọi giá. Ngoài ra, luôn có tùy chọn để tạo ra hai phương thức (trên với lời gọi, và khác mà không có) khi phương thức gọi là chắc chắn nếu nó trong UI Thread hay không. Nó hiếm nhất trong trường hợp hiếm hoi khi bạn nên nhìn vào khía cạnh điều phối này.

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