Записать данные в Application.Exit и показать диалог прогресса - PullRequest
1 голос
/ 11 февраля 2011

Следующий сценарий:

В приложении WPF программа вызывает Log.Write для постановки в очередь сообщений, которые будут записаны на разные выходы (DB, File) в другом потоке. Количество написанных наборов данных может варьироваться от небольших сумм до 50000 и более записей. Пользователь может закрыть приложение каждый раз. Чтобы гарантировать, что все данные будут записаны, даже если пользователь пытается закрыть приложение в Application.Exit вызывается функция Log.Dispose из потока пользовательского интерфейса. Поток пользовательского интерфейса присоединяется к фоновому потоку для ожидания записи всех данных. Это происходит в приложении. Выход.

Теперь было бы здорово показать диалог прогресса во время этого процесса. Проблема в том, что прогресс не движется со следующим кодом:

// Initialize
Log.CurrentInstance.DisposingProgress += new EventHandler<DisposingEventArgs>(Log_DisposingProgress)

// initialize dialog
// ...
_dialog.Show();

Log.Dispose(); // in this method data is written back, threads closed and so on

protected void SetPercentage(DisposingEventArgs e)
{
    if (e.DisposingCompleted)
        _dialog.Close();

    _dialog.Value = e.Percentage;
 }

 // this function is called by a timer which checks the status of the disposing process
 protected void Log_DisposingProgress(object sender, DisposingEventArgs e)
 {
     _dialog.Dispatcher.Invoke(new Action<DisposingEventArgs>(SetPercentage), e);
 }

Я догадался, что проблема возникает, потому что я вызываю Log.Dipose из UI Thread. Поэтому я попытался вызвать Log.Dispose с

new Action(Log.Dispose).BeginInvoke(null, null);

Это заставит индикатор выполнения двигаться, если я вызову Dispose для события, такого как нажатие кнопки, и приложение все еще будет запущено. Если я вызываю его из Application.Exit, я должен предотвратить закрытие приложения. Я пробую это с

new Thread(() => { while(_isDisposing) Thread.Sleep(100); }

но индикатор выполнения все еще не движется в этом случае.

Я попытался запустить другой поток пользовательского интерфейса, в котором должен отображаться диалог прогресса, но программа просто закроется. Поскольку вызов выключения будет все еще обработан, когда я звоню Dispatcher.Run().

Ответы [ 2 ]

1 голос
/ 16 июня 2011

Спустя более длительное время, я попробую это снова.Следующий код делает то, что я хотел достичь:

Log.CurrentInstance.DisposingProgress += new EventHandler<DisposingEventArgs>(Log_DisposingProgress);

var thread = new Thread(() =>
{
    ...
    _dialog.Show();

    while (true)
    {
        lock (currentEventArgsLock)
        {
            if (currentEventArgs != null)
            {
                _dialog.Value = currentEventArgs.Percentage;

                if (currentEventArgs.DisposingCompleted)
                {
                    _dialog.Close();
                    return;
                }
            }
        }

        Thread.Sleep(20);
    }
});


var thread2 = new Thread(() =>
{
    Log.Dispose();
});

thread.Start();
thread2.Start();

// make sure both threads finished
thread.Join();
thread2.Join();

return;


/// <summary>
/// This function is called to notify about progress changes during disposing of Log.
/// </summary>
/// <param name="sender">The sender object.</param>
/// <param name="e">The event arguments</param>
protected void Log_DisposingProgress(object sender, DisposingEventArgs e)
{
    lock (currentEventArgsLock)
    {
        currentEventArgs = e;
    }
}
0 голосов
/ 11 февраля 2011

Вы можете попробовать событие SystemEvents.SessionEnding:

http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents.sessionending.aspx

...