【问题标题】:How can I make a single instance form (not application)?如何制作单个实例表单(不是应用程序)?
【发布时间】:2010-06-21 19:30:21
【问题描述】:

在我的 C# 应用程序中,我有一个可以从菜单命令打开的选项对话框。

我想确保选项对话框只有一个实例(用户不能在给定时间打开多个选项窗口)而不使其成为模态。

此外,如果用户已经打开了这个窗口,并且他在菜单项中单击以再次打开它,则应用程序只会使已经可见的表单成为最顶部的窗口。

谁能指点我如何完成这些任务?

非常感谢。

【问题讨论】:

    标签: c# winforms modal-dialog


    【解决方案1】:

    嗯,最简单的方法是有一个静态字段来存储对单个实例或 null 的引用,然后有一个方法来检索它或创建一个新的。

    请注意,这与将其设置为单例不同 - 因为我假设如果表单已关闭,您下次需要创建一个新实例。 (替代方案 - 隐藏并重用它 - 显示在 STO 的答案中。)您可能想要这样的东西:

    public class OptionsDialog : Form
    {
        private static OptionsDialog openForm = null;
    
        // No need for locking - you'll be doing all this on the UI thread...
        public static OptionsDialog GetInstance() 
        {
            if (openForm == null)
            {
                openForm = new OptionsDialog();
                openForm.FormClosed += delegate { openForm = null; };
            }
            return openForm;
        }
    }
    

    当然,您可能还想让该方法执行“将其置于最前面”的步骤。

    【讨论】:

    • 嗨@Jon,你能举个例子吗?
    • 嗯,我可以看到该请求来自哪里,这不是帖子最初的样子。西部把戏中最快的枪?
    • 是的,当我发表评论时,帖子中没有代码。奇怪!
    • @RHaguiuda: 那里的代码已经存在很长时间了......当您加载页面时它可能没有代码,但我确信它之前有你发表了评论。无论如何;)
    • 让我感到困惑的是,为什么 Microsoft 没有在 .Net Framework 中提供一些简单的方法,让开发人员有机会轻松指定“在任何时候只打开此表单的一个实例”。奇怪。
    【解决方案2】:

    您需要阻止表单关闭。如果不这样做,表单将被丢弃并变得无法使用。您可以通过实现 FormClosing 事件来做到这一点:

        protected override void OnFormClosing(FormClosingEventArgs e) {
            if (e.CloseReason == CloseReason.UserClosing) {
                this.Hide();
                e.Cancel = true;
            }
        }
    

    要使其成为单例,只需在主表单类中跟踪表单的生命周期:

        frmOptions options;
    
        private void btnShowOptions_Click(object sender, EventArgs e) {
            if (options == null) {
                options = new frmOptions();
                // To make absolutely sure:
                options.FormClosed += (o, ea) => options = null;
            }
            else {
                options.WindowState = FormWindowState.Normal;
            }
            options.Show();
        }
    

    【讨论】:

    • 感谢您的回答,您能解释一下(o, ea) => 我知道您将表单设置回null,但我不明白这种语法
    • 这是一个 lambda 表达式。我通常会写 (sender, e) => 但这些名称已经在使用中。
    • 感谢您的澄清
    【解决方案3】:

    您将需要此表单作为属性

    Form1 myForm = null;
    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        myForm = null;
    }
    
    private void ShowForm()
    {
        if (myForm != null)
        {
            myForm.BringToFront();
        }
        else
        {
            myForm = new Form1;
            myForm.Show();
        }
    }
    

    【讨论】:

    • 只需将 myForm 声明为静态,以便我的选项表单 FormClosed 事件可以访问(再次使 myForm = null)。
    【解决方案4】:

    你可以使用这样的代码:

    private MyDialogForm _FormInstance;
    
    public void ShowOptions()
    {
         if (_FormInstance == null)
         {
            _FormInstance = new MyDialogForm();
            _FormInstance.FormClosing += (s,e) => 
            {
                 e.Cancel = true;
                 _FormInstance.Hide();
            }
          }
         _FormInstance.Show();
    }
    

    【讨论】:

      【解决方案5】:

      我假设您至少有两种形式。一种形式,称为 frmMain,允许您打开 frmOptions。在 frmMain 中,添加一个 frmOptions 类型的变量,如下所示:

      public partial class frmMain : Form
      {
           private frmOptions optionsInstance = null;
           ...
      

      在打开“选项”对话框的例程中,添加以下内容:

      if (optionsInstance == null || !optionsInstance.Visible)
      {
           optionsInstance = new frmOptions();
           optionsInstance.Show();
      }
      

      当 frmOptions 关闭时,optionsInstance 不会为空,这就是为什么在实例化 frmOptions 实例之前检查它是否可见的原因。

      如果这对您不起作用,您可以尝试使用互斥锁,但这可能有点矫枉过正。

      【讨论】:

        【解决方案6】:

        基于Jon Skeet's answer,我使用以下代码将表单显示为模式对话框。

                if (this.aboutForm == null)
                {
                    this.aboutForm = new AboutForm();
                    this.aboutForm.FormClosed += (sender2, e2) => { this.aboutForm = null; };
                    this.aboutForm.ShowDialog(this);
                }
                else
                {
                    this.aboutForm.Focus();
                }
        

        我必须这样做,因为我有一个菜单项可以在主窗体的菜单和通知图标的上下文菜单中显示关于窗体。如果我使用主窗体的菜单打开 About 窗体,我仍然可以使用通知图标的上下文菜单项打开另一个实例。

        【讨论】:

          【解决方案7】:
              Main_Frm _main_Frm = null;
          
              private void Show_bt_Click(object sender, EventArgs e)
              {
          
                  if (_main_Frm != null)
                  {
                      _main_Frm .BringToFront();
                  }
                  else
                  {
                      _main_Frm = new Comission_Frm();
                      _main_Frm .Show();
                  }
          
                   //This condition used when you closed the form the form will disposed and when you reopen.
                  if (_main_Frm .IsDisposed)
                  {
                      _main_Frm = new _Main_Frm ();
                      _main_Frm .Show();
                  }
             }
          

          【讨论】:

            【解决方案8】:

            这可能会有所帮助! 注意:以下代码取自以下文章: https://www.dotnetcurry.com/ShowArticle.aspx?ID=150

            static class Program
                {
                    ///<summary>
                    /// The main entry point for the application.
                    ///</summary>
                    [STAThread]
                    static void Main()
                    {
                        bool instanceCountOne = false;
            
                        using (Mutex mtex = new Mutex(true, "MyRunningApp", out instanceCountOne))
                        {
                            if (instanceCountOne)
                            {
                                Application.EnableVisualStyles();
                                Application.SetCompatibleTextRenderingDefault(false);
                                Application.Run(new Form1());
                                mtex.ReleaseMutex();
                            }
                            else
                            {
                                MessageBox.Show("An application instance is already running");
                            }
                        }
                    }
                }
            

            【讨论】:

              猜你喜欢
              • 2012-10-05
              • 2010-11-22
              • 1970-01-01
              • 2012-01-27
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多