繁体   English   中英

C#在关闭应用程序之前如何让后台工作人员完成保存应用程序状态

[英]C# Before closing application how to let background worker finish saving application state

在C#桌面应用程序中,在2种情况下将调用负责保存应用程序状态的后台工作人员。 在应用程序运行时一次。 很好 其他情况是在关闭应用程序时,调用backgroundworker来保存应用程序状态,但是在开始保存之前,该应用程序已关闭并且什么也没有保存。

我试图通过在DoWork和RunWorkerCompleted中使用AutoReset事件类来解决此问题,但由于在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();
}

是WinForms吗?

也许您可以注册OnClosing事件。 在其中,将私有属性IsClosing设置为true。 将事件处理程序e标记为e.Handled = true。

注册到BackgroundWorker事件RunWorkerCompleted。 在其中,检查是否设置了IsClosing属性,在这种情况下,请检查MainForm.Close()应用程序。

编辑:

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

将SaveState代码放在单独的方法中会更清洁,该方法从后台工作程序调用,并且在关闭应用程序时(同步)调用。

要么,要么您可以基于手动重置事件(ManualResetEvent-class)阻止应用程序关闭。

只是提出一个想法。 MainForm上的一个可变的DateTime属性。 (注意-DateTimes不能随便出现,因此可以使用字符串表示形式)

public volatile string _lastUpdated;

每次在后台工作线程上执行save事件时,都会更新此属性。

OnClose将检查DateTime.Now与存储的日期时间之间的时差。

例如:

var timeDiff = DateTime.Now - _lastSavedTime;

如果OnClose检测到timeDiff.TotalSeconds <30(少于30秒),则可以在完成close事件之前从主线程手动触发save事件。

但是,这不能防范Process.Kill-很少有人可以防范。 我只能建议您以一种明智的方式管理您的储蓄。 例如:每次保存到一个新文件,保留最后5次保存。 进行第六次保存后,删除最早的保存等

这是为了解决Process.Kill方案中可能发生的潜在损坏。 意味着如果30秒备份失败,您至少还有60秒的备份时间。

我对这个问题的解决方案是等到backgroundworker异步调用之后添加以下内容,直到backgroundworker完成。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM