在Application.Exit上写入数据并显示进度对话框

时间:2011-02-11 16:31:53

标签: c# .net wpf multithreading dispatcher

以下情景:

在WPF应用程序中,程序调用Log.Write将消息排入队列,这些消息将写入另一个线程中的不同输出(DB,File)。写入的数据集数量可以从少量到50000或更多条目变化。用户每次都可以关闭应用程序。即使用户尝试在Application.Exit上关闭应用程序,也要确保写入所有数据。从UI线程调用Log.Dispose函数。 UI线程加入后台线程,等待所有数据写入。这发生在Application.Exit。

现在,在此过程中显示进度对话框会很棒。问题是,进度没有随着以下代码而移动:

// 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);
 }

我猜到了问题,因为我从UI Thread调用了Log.Dipose。所以我试着用

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

如果我在按钮单击等事件上调用Dispose并且应用程序仍在运行,这将使进度条移动。如果我从Application.Exit调用它,我必须阻止应用程序关闭。我试试

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

但在这种情况下,进度条仍然没有移动。

我尝试启动另一个应该显示进度对话框的UI线程,但程序将关闭。因为当我拨打Dispatcher.Run()时仍会处理关机通话。

2 个答案:

答案 0 :(得分:1)

经过较长时间后,我再试一次。以下代码执行我想要实现的目标:

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;
    }
}

答案 1 :(得分:0)

您可以尝试使用SystemEvents.SessionEnding事件:

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