Ответ 1
Я честно считаю, что BackgroundWorker
является самым изящным решением для этого. Я не могу придумать более простой способ сделать это.
Мне кажется, мне нужны некоторые пояснения относительно использования диспетчера WPF Dispatcher.Invoke и Dispatcher.BeginInvoke.
Предположим, что у меня есть некоторый длинный код работы, такой как тот, который вызывается нажатием кнопки в простом приложении WPF:
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. Это связано с тем, что вызов Dispatcher всегда запускается в потоке пользовательского интерфейса, правильно?
Предполагая это, , что лучше всего подходит для настройки моего диспетчера для выполнения workAction в отдельном потоке из моего пользовательского интерфейса? Я знаю, что могу добавить BackgroundWorker в свой workAction, чтобы предотвратить блокировку моего пользовательского интерфейса как таковой:
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);
Есть ли еще более элегантные способы сделать это, кроме использования BackgroundWorker? Я всегда слышал, что BackgroundWorker причудливый, поэтому мне интересно узнать некоторые альтернативы.
Я честно считаю, что BackgroundWorker
является самым изящным решением для этого. Я не могу придумать более простой способ сделать это.
Ответ на Charlie - это то, что вы ищете, действительно.
Однако, если это возможно, вы можете посмотреть, можете ли вы отменить свою работу, чтобы отдельные единицы работы были небольшими и не влияли на пользовательский интерфейс. Это позволит вам просто использовать диспетчер напрямую. Это хороший пример этого на странице Threading WPF: https://msdn.microsoft.com/en-us/library/ms741870%28v=vs.100%29.aspx
Мне тоже не нравится BackgroundWorker. Простой альтернативой может быть что-то вроде:
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"; }));
}
}
}
Легко, не?
Как видно из названия, оно будет выполняться в фоновом режиме, поэтому вам не нужно создавать экземпляр его с помощью Диспетчера. Плюс, если вы хотите, чтобы этот код запускался в WP7, BeginInvoke не получает фоновый параметр.
Моя рекомендация - создать BackgroundWorker как:
BackgroundWorker worker = new BackgroundWorker;
Затем создайте обработчики для событий:
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork +=new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.ProgressChanged +=new ProgressChangedEventHandler(worker_ProgressChanged);
И, наконец, вы вызываете:
bkwkPlayingLoop.RunWorkerAsync();
Это большой соблазн использовать Диспетчер из DoWork, но вместо этого вызвать employee.ReportProgress() и обработать пользовательский интерфейс оттуда. В противном случае вы столкнетесь с некоторыми несогласованностями с запуском событий завершения.
Задачи проще в использовании, чем фоновые работники, делают больше вещей, имеют меньше проблем и были в значительной степени созданы, поэтому фоновым работникам больше не нужно было использовать...