2009-07-30 15 views
17

ben WPFs Dispatcher.Invoke ve Dispatcher.BeginInvoke kullanım ile ilgili bazı açıklamalar gerekir düşünüyorum.WPF Dispatcher.BeginInvoke ve UI/Arkaplan Konuları

varsayalım Ben öyle ki basit bir WPF uygulamasında bir düğmeye basarak üzerinde çağrıldığında gibi bazı uzun çalışan 'iş' kod:

Bu kod benim kullanıcı arayüzü kilitleniyor

longWorkTextBox.Text = "Ready For Work!"; 
Action workAction = delegate 
    { 
    Console.WriteLine("Starting Work Action"); 
    int i = int.MaxValue; 
    while (i > 0) 
     i--; 
    Console.WriteLine("Ending Work Action"); 
    longWorkTextBox.Text = "Work Complete"; 
    }; 
longWorkTextBox.Dispatcher.BeginInvoke(DispatcherPriority.Background, workAction); 
workAction ederken gerçekleştiriliyor. Bunun nedeni, Dispatcher'ın her zaman UI iş parçacığı üzerinde çalışmasını sağlamasıdır, doğru mu?

bu varsayarsak, benim arayüzünden ayrı bir konu workAction yürütmek için benim dağıtıcınızın yapılandırmak için en iyi yöntem nedir? backgroundworker kullanarak yanında bunu yapmanın bir daha zarif yolu var mı

longWorkTextBox.Text = "Ready For Work!"; 
Action workAction = delegate 
{ 
    BackgroundWorker worker = new BackgroundWorker(); 
    worker.DoWork += delegate 
    { 
     Console.WriteLine("Starting Slow Work"); 
     int i = int.MaxValue; 
     while (i > 0) 
     i--; 
     Console.WriteLine("Ending Work Action"); 
    }; 
    worker.RunWorkerCompleted += delegate 
    { 
     longWorkTextBox.Text = "Work Complete"; 
    }; 
    worker.RunWorkerAsync(); 
}; 
longWorkTextBox.Dispatcher.BeginInvoke(DispatcherPriority.Background, workAction); 

: ben gibi kilitlenmesini benim UI engellemek için benim workAction bir BackgroundWorker ekleyebilir biliyor musunuz? Ben her zaman BackgroundWorker ilginç olduğunu duydum, bu yüzden bazı alternatifleri bilmek merak ediyorum.

cevap

24

Bunun için en şık çözümün BackgroundWorker olduğunu düşünüyorum. Bunu yapmanın daha basit bir yolunu düşünemiyorum.

+0

Yep daha fazla şeyler yapmak, Arkaplan işçilere daha kullanımı daha kolaydır. Bir arka plan iş parçacığında bir şey yapmak istersiniz, ancak işiniz bittiğinde UI iş parçacığını etkiler, BackgroundWorker kullanmak için en kolay şeydir. –

+1

2013'te daha basit bir yol var - async/await: http://stackoverflow.com/questions/12654968/is-async-and-await-exclusively-for-gui-based-asynchronous-programming – Cosmin

+0

Async'i çok seviyorum, ama her şeyle iyi çalışmıyor. Ama bu oldukça iyi bir seçenek! – Malavos

4

Charlie'nin cevabı gerçekten aradığınız şey.

Ancak, eğer mümkünse, çalışmalarınızı birbirinden ayırabilecek olup olmadığına bakabilir ve böylece her bir iş birimi küçüktür ve UI'yi etkilemez. Bu, yalnızca Doğrudan Satış görevlisi kullanmanıza izin verir. Bunun WPF Threading sayfasında iyi bir örneği vardır: https://msdn.microsoft.com/en-us/library/ms741870%28v=vs.100%29.aspx

+0

Konuyla ilgili harika yazı! –

+0

Evet ... genellikle MSDN minimumdur, ancak bu makale gerçekten eksiksiz. WPF'de async programlama hakkında daha fazla bilgi için –

+0

okuyabilirsiniz: http://www.a2zdotnet.com/View.aspx?Id=93. – frameworkninja

2

Adından da anlaşılacağı gibi, arka planda çalışacağını belirtir, böylece bunu Dispatcher ile başlatmanız gerekmez. Artı, bu kodun bir WP7'ye çalışmasını istiyorsanız, BeginInvoke arka plan parametresini alamaz. olaylara işleyici oluşturmak sonra

BackgroundWorker worker = new BackgroundWorker; 

Ve:

Benim tavsiye olarak backgroundworker yaratmaktır

worker.WorkerReportsProgress = true; 
worker.WorkerSupportsCancellation = true; 
worker.DoWork +=new DoWorkEventHandler(worker_DoWork); 
worker.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 
worker.ProgressChanged +=new ProgressChangedEventHandler(worker_ProgressChanged); 

Ve nihayet aramak:

bkwkPlayingLoop.RunWorkerAsync(); 

Öyle Dispatcher'ı DoWork'un içinden kullanmak için büyük bir caziplik ama bunun yerine worker.ReportProgress() ve UI'yi oradan halledin. Aksi takdirde fesih olaylarının ateşlenmesi ile bazı tutarsızlıklarla karşılaşacaksınız.

4

Ben de BackgroundWorker'ı sevmiyorum. ,

using System; 
using System.Threading; 
using System.Windows; 

namespace Sample 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     protected override void OnSourceInitialized(EventArgs e) 
     { 
      base.OnSourceInitialized(e); 
      longWorkTextBox.Text = "Ready For Work!"; 
     } 

     private void startButton_Click(object sender, RoutedEventArgs e) 
     { 
      new Thread(Work).Start(); 
     } 

     void Work() 
     { 
      longWorkTextBox.Dispatcher.BeginInvoke((Action)(() => { longWorkTextBox.Text = "Working..."; })); 
      Console.WriteLine("Starting Work Action"); 
      int i = int.MaxValue; 
      while (i > 0) 
       i--; 
      Console.WriteLine("Ending Work Action"); 
      longWorkTextBox.Dispatcher.BeginInvoke((Action)(() => { longWorkTextBox.Text = "Work Complete"; })); 
     } 
    } 
} 

Kolay değil: basit bir alternatifi gibi bir şey olabilir?

0

Görevler ... az sorunları var ve Arka Plan İşçileri artık kullanılamaz gerek yoktu bu yüzden hemen hemen yaratıldı,

+0

Bazı örnekler kullanabilir misiniz? – LuckyLikey

+0

Arka plandaki çalışan, Görevler tarafından etkin bir şekilde kullanımdan kaldırıldı ... http://blog.stephencleary.com/2013/05/taskrun-vs-backgroundworker-intro.html – MattE

+0

İyi .. bu bağlantı için teşekkürler. WPF'de arka plan yapmak için iyi bir yoldur. Sanırım bu diziye derinden bakacağım. – LuckyLikey