单实例 Windows Forms 应用程序,支持最小化到系统托盘

5

我有一个名为“Restoring.exe”的WinForm应用程序。当最小化窗口时,它会移动到系统托盘并隐藏在任务栏中。如果我点击系统托盘中的通知图标,则窗口将前置显示。

public void notifyicon_MouseClick(object sender, System.EventArgs e)
{
    notifyicon.Visible = false;
    Show();
    Activate();
    TopMost = true;
    BringToFront();
    this.WindowState = FormWindowState.Normal;
}

但是我的实际需求是,当第二次单击应用程序时,需要从系统托盘中还原应用程序。

为此,我尝试了以下代码:

Program.cs:

static void Main()
{
    if (IsServiceManagerAlreadyRunning())
    {
        Form1 form1 = new Form1();
        form1.Restore();
    }
    else
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

Form1.cs:

public void Restore()
{
    notifyicon.Visible = false;
    Show();
    Activate();
    TopMost = true;
    BringToFront();
    this.WindowState = FormWindowState.Normal;
} 

我的实际问题是,如果应用程序已经在运行,'Restore'方法就会触发,列出的所有操作都将运行,并且窗口将出现在前面。但是,在完成这些操作后,窗口再次回到系统托盘中,而不是停留在前台。请问有人能提供解决方案吗?

http://www.hanselman.com/blog/TheWeeklySourceCode31SingleInstanceWinFormsAndMicrosoftVisualBasicdll.aspx - Hans Passant
3个回答

6

创建单实例

向您的项目添加对Microsoft.VisualBasic.dll的引用,并将此类添加到您的项目中:

using System;
using Microsoft.VisualBasic.ApplicationServices;
using System.Windows.Forms;

namespace Sample
{
    public class ApplicationController : WindowsFormsApplicationBase
    {
        private Form mainForm;
        public ApplicationController(Form form)
        {
            //We keep a reference to main form 
            //To run and also use it when we need to bring to front
            mainForm = form;
            this.IsSingleInstance = true;
            this.StartupNextInstance += this_StartupNextInstance;
        }

        void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e)
        {
            //Here we bring application to front
            e.BringToForeground = true;
            mainForm.ShowInTaskbar = true;
            mainForm.WindowState = FormWindowState.Minimized;
            mainForm.Show();
            mainForm.WindowState = FormWindowState.Normal;
        }

        protected override void OnCreateMainForm()
        {
            this.MainForm = mainForm;
        }
    }
}

然后在你的 Program.cs 中使用那个 ApplicationController 来运行程序:

using System;
using System.Windows.Forms;

namespace Sample
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            //create a controller and Pass an instance of your application main form
            var controller =  new Sample.ApplicationController(new YourMainForm());

            //Run application
            controller.Run(Environment.GetCommandLineArgs());
        }
    }
}

现在您的应用程序是单实例的,当您单击exe文件时,不会运行另一个实例,而是将现有实例带到前台。

使用NotifyIcon

在主窗体上放置一个NotifyIcon,然后当您单击最小化按钮时隐藏窗口,并在单击通知图标时显示窗口,您可以处理这些事件:

//When click on notify icon, we bring the form to front
private void notifyIcon_Click(object sender, EventArgs e)
{
    this.ShowInTaskbar = true;
    this.WindowState = FormWindowState.Minimized;
    this.Show();
    this.WindowState = FormWindowState.Normal;
}

//here we check if the user minimized window, we hide the form
private void ApplicationMainForm_Resize(object sender, EventArgs e)
{
    if (this.WindowState == FormWindowState.Minimized)
    {
        this.ShowInTaskbar = false;
        this.Hide();
    }
}

//when the form is hidden, we show notify icon and when the form is visible we hide it
private void ApplicationMainForm_VisibleChanged(object sender, EventArgs e)
{
    this.notifyIcon1.Visible = !this.Visible;
}

@KathirSubramaniam 没问题,欢迎使用 :)。这里可以正常工作,请问您有什么问题吗? - Reza Aghaei
@KathirSubramaniam 是的,你可以发邮件到r.aghaei@outlook.com。我仔细检查了代码和我的示例,它们都正常工作。也许是你做错了什么,唯一需要更改的是上面代码中单个实例的名称,即你的主窗体名称。 - Reza Aghaei
@KathirSubramaniam 你好,Kathir。我检查了你的代码,正如我所说的,你在执行一些事情时犯了一些错误。你正在将互斥解决方案与此应用程序控制器解决方案混合使用,这是行不通的。要想使用此应用程序控制器创建单个应用程序,你唯一需要做的就是将我的代码放入你的program.cs中,并在我的代码中使用new Form1()而不是new YourMainForm() - Reza Aghaei
@KathirSubramaniam,我认为你也应该阅读我的回答中关于使用NotifyIcon的部分。我强烈推荐我编写代码的方式。 - Reza Aghaei

1
问题在于 main() 中 if 块的两个分支都创建了一个新表单,因此您没有对已经运行的表单做任何处理。
如果程序已经有一个实例正在运行(IsServiceManagerAlreadyRunning() == true?),则需要查找第一个实例中的窗口并激活它,而不是创建一个新的表单。
您可以尝试通过窗口标题或更复杂的解决方案来查找窗口。在 Google 上搜索“Windows 应用程序单个实例”会返回许多文章。

-2

我认为这是你需要的东西:

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


        private void notifyIcon1_Click(object sender, EventArgs e)
        {
            this.Show();
            this.WindowState = FormWindowState.Normal;
        }

        private void Form1_ResizeBegin(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                this.Hide();
            }
        }

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接