【问题标题】:Should my Wait Dialog implement Singleton pattern?我的等待对话框应该实现单例模式吗?
【发布时间】:2011-05-09 19:34:48
【问题描述】:

我目前正在处理我的个人等待对话框实现,它支持任务进度更新和任务取消。 ATM 是这样的:

public partial class WaitDialog : Form
{
    WaitDialog()
    {
        InitializeComponent();
    }

    public static WaitDialog Instance
    {
        get { return WaitDialogCreator.uniqueInstance; }
    }

    public DialogResult ShowDialog(Form owner, string message)
    {
        Instance.lblWaitMessage.Text = message;

        return Instance.ShowDialog(owner);
    }

    public DialogResult ShowDialog(Form owner, BackgroundWorker worker)
    {
        ...
    }

    public DialogResult ShowDialog(Form owner, string message, BackgroundWorker worker)
    {
        ...
    }

    private class WaitDialogCreator
    {
        static WaitDialogCreator() { }

        internal static readonly WaitDialog uniqueInstance = new WaitDialog();
    }
}

在我的 ShowDialog() 方法中,我可以传递一个工作对象参数,以便我可以设置一些取决于其属性的属性/处理程序,例如使用的进度条的类型(如果报告进度更改则为选取框,否则为连续)、取消任务的可能性(根据 WorkerSupportsCancellation 属性)等。方法如下所示:

    public DialogResult ShowDialog(Form owner, BackgroundWorker worker)
    {
        if (worker == null)
        {
            throw new ArgumentNullException("worker", "A non-null worker must be provided.");
        }
        else
        {
            Instance.btnCancel.Enabled = worker.WorkerSupportsCancellation;

            //This handler close the dialog
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(onWorkerWorkComplete);

            if (worker.WorkerReportsProgress)
            {
                Instance.pbProgress.Style = ProgressBarStyle.Continuous;

                //Update the progress bar
                worker.ProgressChanged += new ProgressChangedEventHandler(onWorkerProgressChanged);
            }

            if (worker.WorkerSupportsCancellation)
            {
                Instance.btnCancel.Click += (sender, e) => { worker.CancelAsync(); };
            }
        }

        return Instance.ShowDialog(owner);
    }

我会以这种方式通过父表单上的控制器访问等待对话框:

    public Controller(Form window)
    {
        this.window = window;
        this.waitDialog = WaitDialog.Instance;
    }

    ...

    public void ShowWaitDialog(BackgroundWorker worker)
    {
        if (worker == null)
        {
            this.ShowWaitDialog();
        }
        else
        {
            window.BeginInvoke((MethodInvoker)delegate() { waitDialog.ShowDialog(window, worker); });
        }
    }

也许这是一个非常愚蠢的问题,但这里是:在这种情况下应用(像我一样)单例模式是否正确,或者我应该选择正常的实例创建,因为 WaitDialog 类结束通常会处理更多比其生命周期中的 BackGroundWorker?

让我想知道的是,每次我在对 ShowDialog(Form, BackGroundWorker) 的调用中传递一个新的 BackGroundWorker 时,我都可以(而且我将)修改 WaitDialog 的单个实例属性。 根据模式,这是正确的行为吗?我可以采取其他途径来更好地实施吗?我愿意接受任何建议。

【问题讨论】:

    标签: c# winforms singleton backgroundworker


    【解决方案1】:

    我每次都会创建一个新实例。

    我不使用单例的原因是因为表单除了使用一个特定的等待操作之外没有任何意义。当您只想设置一个类的实例并反复使用该实例及其特定设置时,可以使用单例模式。

    【讨论】:

      【解决方案2】:

      不,这是个坏主意。 Form 类在很大程度上被设计为一次性类。一旦一个表单对象被处理掉,它就死了,不能被复活。当您尝试再次显示它时,您将得到一个 ObjectDisposedException。为了防止这种情况,您必须拦截 FormClosing 事件并停止默认处理。您可以调用 Hide() 并设置 e.Cancel = true。但是现在当你真的想摆脱它时,你却遇到了杀死它的麻烦。

      但也许更令人信服的是,您应该只缓存创建起来非常昂贵但不占用大量资源的对象。 Form 类正好相反。创建它很便宜,但需要非常大量的托管和非托管资源。尤其是后者,窗口是一个非常昂贵的操作系统对象。它可能看起来创建一个表单很昂贵,但您看到的是在绘制表单时消耗的周期。当您显示隐藏表单时,您将燃烧完全相同的周期数。

      【讨论】:

      • 这是一个有趣的观点。所以基本上创建/显示一次/销毁表单与缓存它并显示/隐藏多次没有太大区别......所以我将为每个后台操作重新创建表单。谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-24
      • 1970-01-01
      • 2016-09-21
      • 2012-01-18
      • 2013-07-15
      相关资源
      最近更新 更多