我的等待对话框应该实现单例模式吗?

发布于 2024-10-01 20:57:03 字数 2756 浏览 0 评论 0原文

我目前正在开发我个人的等待对话框实现,它支持任务进度更新和任务取消。 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 的单实例属性。 根据模式,这是正确的行为吗?我可以采取其他途径来更好地实施吗?我愿意接受任何建议。

i'm currently working on my personal Wait Dialog implementation, wich supports task progress update and task cancellation. ATM it is something like:

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

In my ShowDialog() method I can pass a worker object parameter, so that i can set some properties/handlers that depends on its properies, such as the type of progress bar used (marquee if it reports progress changes, continuous otherwise), the possibility to cancel the task (according to WorkerSupportsCancellation prop), etc. The method looks like this:

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

I would access the wait dialog thru a controller on my parent form in this way:

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

Maybe that's a very noobish question, but here it is: is it correct to apply (as I do) the Singleton Pattern in this case, or shoud i opt for normal instance creation, given that WaitDialog class ends will normally handle more than a BackGroundWorker in its lifecycle?

The thing that makes me wonder is that I can (and i will) modify WaitDialog's single instance properties each time I pass a new BackGroundWorker in my call to ShowDialog(Form, BackGroundWorker).
Is it a correct behavior, according to the pattern? Are there other path i can take for a better implementation? I am open to any suggestion.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

潇烟暮雨 2024-10-08 20:57:03

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

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

I would creating a new instance every time.

The reason I would not use a singleton is because the form does not have any meaning beyond the use of one specific wait operation. Singleton patterns are used when you want to setup an instance of a class only once and re-use that instance over and over, with its specific settings.

你是年少的欢喜 2024-10-08 20:57:03

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

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

No, it's a bad idea. The Form class was very much designed as a single-use class. Once a form object is disposed it is dead and cannot be revived. You'll get an ObjectDisposedException when you try to display it again. To prevent this, you'll have to intercept the FormClosing event and stop the default processing. You could call Hide() and set e.Cancel = true. But now you've got the hassle of killing it when you really want to get rid of it.

But perhaps more convincingly, you should only ever cache objects that are very expensive to create but don't take a lot of resources. The Form class is the exact opposite. Creating it is cheap but it takes a very large amount of both managed and unmanaged resources. Especially the latter, a window is a very costly OS object. It may look like a Form is expensive to create but what you see is the cycles that are burned on painting the form. You'll burn the exact same number of cycles when you show a hidden form.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文