1

У меня есть 2 асинхронных процесса, которые нуждаются в, которые будут называться один за другим (один из них представляет собой создание XML backgroundworker, а другой - ROW BW, который использует файлы XML, созданные в первом процессе). Основной причиной этих потоков является прекращение замораживания пользовательского интерфейса и предоставление обновления статуса путем выполнения индикатора прогресса - поскольку такой синхронный подход нежелателен/возможен.Подождите завершения BackgroundWorker?

if (!CreateXMLBW.IsBusy) 
{ 
CreateXMLBW.RunWorkerAsync(""); 
} 
if (!CreateRarBW.IsBusy) 
{ 
CreateRarBW.RunWorkerAsync(); 
}

Я не могу поставить второй BW в случае завершения первом, поскольку данные процессы могут быть использованы отдельно, и как таковой, если я просто хочу, чтобы создать XML-файлы, которые я могу сделать это.

Я пробовал использовать AutoResetEvent и WaitOne, но это (по какой-либо причине) все еще не работает.

Есть ли другие способы, которые я могу дождаться завершения BW без замораживания основного потока пользовательского интерфейса?

+0

Почему вы не создаете нового Работника, который работает с этими двумя рабочими синхронно? и вы запускаете этого нового рабочего async – Fabske

+0

Мне нравится эта идея, но идет против DRY. –

+0

Сухо, вы не повторяете код при повторном использовании двух других рабочих. В любом случае решение задачи, предложенное ниже, намного более изящно :) – Fabske

ответ

1

Ваш сценарий - именно то, для чего был рассчитан Task. В вашем конкретном случае ваш код может выглядеть следующим образом:

public delegate void UpdateUI(int progress); 

private void RunOneAfterAnotherAsync() 
{ 
    Task<XmlElement> task = Task.Factory.StartNew<XmlElement>(CreateXMLBW); 
    task.ContinueWith(CreateRarBW); 
} 

private XmlElement CreateXMLBW() 
{ 
    // your code 

    // progress 
    progressBar1.Invoke((UpdateUI)UpdateProgressBar, new object[] {progressValue}); 

    // result 
    XmlDocument doc = new XmlDocument(); 
    return doc.CreateElement("element"); 
} 

private void CreateRarBW(Task<XmlElement> task) 
{ 
    CreateRarBW(task.Result); 
} 

private void CreateRarBW(XmlElement arg) 
{ 
    // your code 
} 

public void UpdateProgressBar(int value) 
{ 
    this.progressBar1.Value = value; 
} 

RunOneAfterAnotherAsync не блокирует и ваши 2 методов выполняются асинхронно один за другим. CreateRarBW запускается только в том случае, если CreateXMLBW заканчивается без исключения, но вы можете изменить его, используя дополнительные аргументы в ContinueWith.

Вы можете сделать гораздо больше, чем показано в этом примере - я рекомендую вам изучить класс Task.

EDIT

У меня есть расширить пример немного, чтобы включать в себя результат, передаваемой от первой задачи на второй. Также добавлен пример выполнения пользовательского интерфейса.

+0

Могу ли я сообщить о прогрессе или похож на индикатор выполнения из задачи без исключения перекрестной резьбы? –

+1

Чтобы сообщить о прогрессе, вам нужно вызвать делегата из своей задачи. Если вы хотите обновить интерфейс непосредственно из задачи, вы должны использовать 'Control.Invoke'. –

+0

Добавлен код примера выполнения. –

1

Если вы не хотите заблокировать пользовательский интерфейс, пока в ожидании события (так что я полагаю, ты собираешься сделать что-то) вы можете вызвать событие в конце DoWork() и UI поток может его получит.

Если вы используете 4.0 и можете избежать использования BackgroundWorker, вы можете использовать Task.ContinueWith из TPL.

псевдокод может выглядеть следующим образом:

Action action =(() => DoWorkMethod()); 
    Task.Factory.StartNew(() => action()).ContinueWith(()=>CallAfterComplete()); 
1

Вы также можете использовать Task как в этом примере:

class Program 
{ 
    static XElement CreateXml() 
    { 
     System.Threading.Thread.Sleep(1000); 
     return XElement.Parse(@"<FooBar>Hi!</FooBar>"); 
    } 

    static void ProceedXml(XElement xml) 
    { 
     System.Threading.Thread.Sleep(1000); 
     Console.WriteLine(xml.ToString()); 
    } 

    public static void Main() 
    { 
     Task.Factory.StartNew<XElement>(CreateXml) 
        .ContinueWith(t => ProceedXml(t.Result)); 
     Console.ReadKey(); 
    } 
} 
0

Ваш UI может обрабатывать RunWorkerCompleted событие на первом BW и вызовите вторую BW.

+0

В соответствии с моим вопросом - «Я не могу поместить второй BW в событие завершения первого, поскольку процессы могут использоваться отдельно и как таковые, если я просто хочу создавать файлы XML, я могу это сделать». Значение, если я поместил его в событие RunWorkerCompleted, он всегда будет запускаться, чего я не хочу. –

+0

@Myles Ну, хорошо, но я предположил, что ваш пользовательский интерфейс будет знать, хочет ли он запускать вторую BW или нет. Я не хотел, чтобы вы все-таки запустили его. – Martin

Смежные вопросы