2016-01-27 1 views
1

В настольном приложении C# в двух ситуациях вызывается фоновый работник, ответственный за сохранение состояния приложения. Когда приложение запущено. Это прекрасно работает. Другое, когда приложение закрывается, вызывается фоновый рабочий, чтобы сохранить состояние приложения, но прежде чем он начнет сохранять, приложение закрывается и ничего не сохраняется.C# Перед тем как закрыть приложение, чтобы позволить фоновому работнику закончить сохранение состояния приложения

Я попытался решить проблему, используя класс событий AutoReset в DoWork и RunWorkerCompleted, но не работал, потому что приложение закрыто до того, как backgroundworker может сэкономить все.

Вопрос: как я могу сделать основной поток до тех пор, пока фоновая работа не завершит сохранение?

private void frmMain_FormClosing(object sender, FormClosingEventArgs e) 
{ 
    this.saveAHToolStripMenuItem_Click(this, e); 
} 

private void saveAHAsToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    this.backgroundWorkerMain1.RunWorkerAsync(args); 
} 

private void backgroundWorkerMain1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    saveMethod(); 
} 

private void backgroundWorkerMain1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    showResultOfSaving(); 
} 
+2

не закрываются, пока это событие не срабатывает: https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.runworkercompleted(v=vs.110).aspx Если вы показать некоторые из ваших работ, мы могли бы помочь больше. – Pogrindis

+0

Спасибо за вашу рекомендацию. Я обновил свой вопрос с помощью базовой структуры кода. Здесь FormClosing завершается, прежде чем сохранение будет завершено backgroundWorker. – Saad

+0

Привет, я добавил решение как Изменить в свой ответ ниже. – KarmaEDV

ответ

0

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

while (this.backgroundWorkerMain1.IsBusy) 
{ 
    Application.DoEvents(); 
} 
0

Было бы чище, чтобы поместить SaveState код в отдельный метод, который вызывается из фона рабочего и (синхронно) при закрытии приложения.

Либо это, либо вы можете заблокировать приложение от закрытия на основе события ручного сброса (ManualResetEvent-class).

+0

Я собираюсь проверить, может ли ManualResetEvent использовать внутри основного потока, не блокируя его. Ваше первое синхронное предложение похоже на предложение Baaleos, чтобы сохранить его в основном методе закрытия. – Saad

+0

ok Я проверил ManualResetEvent, приложение зависало, когда я вызвал WaitOne() в основном потоке и закрыл перед сохранением, когда вызвал его внутри DoWork(). – Saad

1

Это WinForms?

Возможно, вы можете зарегистрироваться в событии OnClosing. Внутри него задайте для закрытого свойства IsClosing значение true. Отметьте обработчик события e как e.Handled = true.

Зарегистрировать событие BackgroundWorker RunWorkerCompleted. В нем проверьте, установлено ли свойство IsClosing и в этом случае приложение MainForm.Close().

Edit:

using System; 
using System.Threading; 
using System.Windows.Forms; 
using System.ComponentModel; 

namespace BgWorker 
{ 
    public partial class Form1 : Form 
    { 
     BackgroundWorker _bgWorker; 
     bool _iNeedToCloseAfterBgWorker; 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     void Form1_Load(object sender, EventArgs e) 
     { 
      _bgWorker = new BackgroundWorker(); 
      _bgWorker.DoWork += _bgWorker_DoWork; 
      _bgWorker.RunWorkerCompleted += _bgWorker_RunWorkerCompleted; 
     } 

     void _bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      MessageBox.Show("Done!"); 

      if (_iNeedToCloseAfterBgWorker) 
       Close(); 
     } 

     void _bgWorker_DoWork(object sender, DoWorkEventArgs e) 
     { 
      // Do long lasting work 
      Thread.Sleep(2000); 
     } 

     void btnWorkIt_Click(object sender, EventArgs e) 
     { 
      // Note how the Form remains accessible 
      _bgWorker.RunWorkerAsync(); 
     } 

     void Form1_FormClosing(object sender, FormClosingEventArgs e) 
     { 
      if (_iNeedToCloseAfterBgWorker || _bgWorker.IsBusy) return; 
      e.Cancel = true; 
      _iNeedToCloseAfterBgWorker = true; 
      _bgWorker.RunWorkerAsync(); 
     } 
    } 
} 
+0

Да, это WinForms. Я не мог следовать твоему предложению. Как он включит DoWork(), прежде чем продолжить выполнение более поздних операторов в FormClosing()? – Saad

+0

Привет, Я добавил решение как Изменить – KarmaEDV

+0

Решение уже доступно. Если фоновой рабочий занят, я не хочу возвращаться, но хочу продолжать ждать до его завершения. – Saad

0

Просто бросать идею там. Возможно, изменчивое свойство DateTime в MainForm. (Примечание - DateTimes не может быть энергозависимой оказывается, так что вы могли бы использовать строковое представление вместо)

public volatile string _lastUpdated; 

Это свойство обновляется каждый раз, когда сохранение событий осуществляется на фоне рабочего потока.

OnClose проверяет разницу во времени между DateTime.Now и временем хранения.

Например:

var timeDiff = DateTime.Now - _lastSavedTime; 

Если OnClose обнаруживает, что timeDiff.TotalSeconds является < 30 (менее 30 секунд) Вы можете вызвать сохранение события вручную из главного потока, до близкого события завершается.

Это, однако, не защитит от Process.Kill - очень мало можно защитить от этого. Все, что я могу предложить, это то, что вы управляете своими экономиями в разумном ключе. Например: каждый раз сохраняйте новый файл, сохраняя последние 5 сейвов. Когда сделано 6-е сохранение, удалите старое сохранение и т. Д.

Это объясняет потенциальное повреждение, которое может произойти из сценария Process.Kill. Это означает, что вы по-прежнему будете иметь резервную копию не менее 60 секунд, если произойдет сбой 30-секундной резервной копии.

+0

Да, при закрытии я также подумал о том, чтобы сохранить его в Главном потоке отдельно, но backgroundworker передается как параметр в рутине сохранения. Я думал, что это может быть дополнено репрессивным кодом. – Saad

+0

Перед сохранением я прошу пользователя сохранить или нет, поэтому мне не нужно проверять разницу во времени. – Saad

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