简体   繁体   English

最小化托盘 C# WinForms 应用程序的正确方法是什么?

[英]What's the proper way to minimize to tray a C# WinForms app?

What is the proper way to minimize a WinForms app to the system tray?将 WinForms 应用程序最小化到系统托盘的正确方法是什么?

Note: minimize to system tray ;注意:最小化到系统托盘 on the right side of the taskbar by the clock.在时钟的任务栏右侧。 I'm not asking about minimizing to taskbar, which is what happens when you hit the "minus" button on the window.我不是在问最小化到任务栏,这是当您点击窗口上的“减号”按钮时会发生的情况。

I've seen hackish solutions like, "minimize, set ShowInTaskbar = false, then show your NotifyIcon."我见过一些骇人听闻的解决方案,例如“最小化,设置 ShowInTaskbar = false,然后显示您的 NotifyIcon”。

Solutions like that are hackish because the app doesn't appear to minimize to the tray like other apps, the code has to detect when to set ShowInTaskbar = true, among other issues.像这样的解决方案是骇人听闻的,因为该应用程序似乎不像其他应用程序那样最小化到托盘,代码必须检测何时设置 ShowInTaskbar = true,以及其他问题。

What's the proper way to do this?这样做的正确方法是什么?

There is actually no managed way to do that form of animation to the tray in native winforms, however you can P/Invoke shell32.dll to do it: 实际上没有托管方式在本机winforms中对托盘执行这种形式的动画,但是您可以通过P / Invoke shell32.dll来执行此操作:

Some good info here (In the comments not the post): 这里有一些好的信息(在评论中不是帖子):

http://blogs.msdn.com/jfoscoding/archive/2005/10/20/483300.aspx http://blogs.msdn.com/jfoscoding/archive/2005/10/20/483300.aspx

And here it is in C++: 在这里它是在C ++中:

http://www.codeproject.com/KB/shell/minimizetotray.aspx http://www.codeproject.com/KB/shell/minimizetotray.aspx

You can use that to figure out what stuff to Pinvoke for your C# version. 您可以使用它来确定Pinvoke为您的C#版本提供的内容。

this.WindowState = FormWindowState.Minimized  

That is the built in way to do it and it looks fine to me most of the time. 这是内置的方式,它在大多数时候对我来说很好看。 The only time is has some weirdness to it is if you call it on startup which has some weirdness sometimes which is why most people will also set the ShowInTaskbar = false and hide the form too. 唯一的一次是有一些奇怪的是,如果你在启动时调用它有时会有一些奇怪,这就是为什么大多数人也会设置ShowInTaskbar = false并隐藏表单。

http://msdn.microsoft.com/en-us/library/system.windows.forms.form.windowstate.aspx http://msdn.microsoft.com/en-us/library/system.windows.forms.form.windowstate.aspx

It will helps: 它会有所帮助:

public partial class Form1 : Form
{
    public static bool Close = false;
    Icon[] images;
    int offset = 0;

    public Form1()
    {
        InitializeComponent();

        notifyIcon1.BalloonTipText = "My application still working...";
        notifyIcon1.BalloonTipTitle = "My Sample Application";
        notifyIcon1.BalloonTipIcon = ToolTipIcon.Info; 
    }

    private void Form1_Resize(object sender, EventArgs e)
    {
        if (FormWindowState.Minimized == WindowState)
        {
            this.Hide();
            notifyIcon1.ShowBalloonTip(500);
            //WindowState = FormWindowState.Minimized;
        }
    }

    private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
    {
        this.Show();
        notifyIcon1.ShowBalloonTip(1000);
        WindowState = FormWindowState.Normal;
    }

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

    private void closeToolStripMenuItem_Click(object sender, EventArgs e)
    {
        Close = true;
        this.Close();  
    }

    // Handle Closing of the Form.
    protected override void OnClosing(CancelEventArgs e)
    {
        if (Close)
        {
            e.Cancel = false;
        }
        else
        {
            WindowState = FormWindowState.Minimized;
            e.Cancel = true;
        }
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        // Load the basic set of eight icons.
        images = new Icon[5];
        images[0] = new Icon("C:\\icon1.ico");
        images[1] = new Icon("C:\\icon2.ico");
        images[2] = new Icon("C:\\icon3.ico");
        images[3] = new Icon("C:\\icon4.ico");
        images[4] = new Icon("C:\\icon5.ico");
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        // Change the icon.
        // This event handler fires once every second (1000 ms).
        if (offset < 5)
        {
            notifyIcon1.Icon = images[offset];
            offset++;
        }
        else
        {
            offset = 0;
        }
    }
}

This code is tested and supports many options. 此代码经过测试并支持许多选项。

More here: http://code.msdn.microsoft.com/TheNotifyIconExample 更多信息: http//code.msdn.microsoft.com/TheNotifyIconExample

Update: Looks like I posted too soon. 更新:看起来我发布的太快了。 I was also using the below hack for a tool of mine. 我也使用下面的黑客攻击我的工具。 Waiting for the right solution for this.......... 等待正确的解决方案..........

You can use Windows.Forms.NotifyIcon for this. 您可以使用Windows.Forms.NotifyIcon。 http://msdn.microsoft.com/en-us/library/system.windows.forms.notifyicon.aspx http://msdn.microsoft.com/en-us/library/system.windows.forms.notifyicon.aspx

Add NotifyIcon to the form, set some properties and you are done. 将NotifyIcon添加到表单,设置一些属性,您就完成了。

        this.ShowIcon = false;//for the main form
        this.ShowInTaskbar = false;//for the main form
        this.notifyIcon1.Visible = true;//for notify icon
        this.notifyIcon1.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon1.Icon")));//set an icon for notifyicon

    private void Form1_Shown(object sender, EventArgs e)
    {
        this.Hide();
    }

Similar as above... 与上面类似......

I have a resize event handler that is triggered whenever the window gets resized (Maximized, minimized, etc.)... 我有一个resize事件处理程序,只要窗口调整大小(最大化,最小化等)就会触发...

    public form1()
    {
       Initialize Component();

       this.Resize += new EventHanlder(form1_Resize);
    } 


    private void form1_Resize(object sender, EventArgs e)
    {
       if (this.WindowState == FormWindowState.Minimized && minimizeToTrayToolStripMenuItem.Checked == true)
       {
             NotificationIcon1.Visible = true;
             NotificationIcon1.BalloonTipText = "Tool Tip Text"
             NotificationIcon1.ShowBalloonTip(2);  //show balloon tip for 2 seconds
             NotificationIcon1.Text = "Balloon Text that shows when minimized to tray for 2 seconds";
             this.WindowState = FormWindowState.Minimized;
             this.ShowInTaskbar = false;
       }
    }

This allows the user to select whether or not they want to minimize to tray via a menubar. 这允许用户选择他们是否想要通过菜单栏最小化到托盘。 They can go to Windows -> and click on Minimize to Tray. 他们可以转到Windows - >并单击最小化到托盘。 If this is checked, and the window is being resized to Minimized, then it will minimize to the tray. 如果选中此选项,并且窗口的大小调整为最小化,则它将最小化到托盘。 Works flawlessly for me. 对我来说完美无瑕。

I have programmed a quick solution for you guys, this might not be the most efficient way (I'm not sure), but it definitely works !我已经为你们编写了一个快速解决方案,这可能不是最有效的方法(我不确定),但它绝对有效!

The below solution successfully minimizes your Winforms application to the system Tray, and by using the notify Icon you create a small icon in the system tray with the aforementioned menu items.下面的解决方案成功地将您的 Winforms 应用程序最小化到系统托盘,并通过使用通知图标在系统托盘中创建一个带有上述菜单项的小图标。 than we use the in-built libraries to fetch the Window (GUI in this case), and using the appropriate methods with Booleans we then minimize the window to the tray.比我们使用内置库来获取窗口(在这种情况下为 GUI),然后使用适当的方法和布尔值,我们将窗口最小化到托盘。

private void TransformWindow()
        {
            ContextMenu Menu = new ContextMenu();

            Menu.MenuItems.Add(RestoreMenu);
            Menu.MenuItems.Add(HideMenu);
            Menu.MenuItems.Add(new MenuItem("Exit", new EventHandler(CleanExit)));

            notifyIcon = new NotifyIcon()
            {
                Icon = Properties.Resources.Microsft_Icon,
                Text = "Folder Watcher",
                Visible = true,
                ContextMenu = Menu
            };
            processHandle = Process.GetCurrentProcess().MainWindowHandle;
            ResizeWindow(false);

        }
        #region Getting Libraries
        [DllImport("user32.dll")]
        public static extern IntPtr GetShellWindow();
        [DllImport("user32.dll")]
        public static extern IntPtr GetDesktopWindow();
        public const Int32 SwMINIMIZE = 0;
        public const Int32 SwMaximize = 9;

        [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern IntPtr GetConsoleWindow();

        [DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ShowWindow([In] IntPtr hWnd, [In] Int32 nCmdShow);
        public static void MinimizeConsoleWindow()
        {
            IntPtr hWndConsole = processHandle;
            ShowWindow(hWndConsole, SwMINIMIZE);

        }
        public static void MaximizeConsoleWindow()
        {
            IntPtr hWndConsole = processHandle;
            ShowWindow(hWndConsole, SwMaximize);

        }
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
        public static void ResizeWindow(bool show)
        {
            RestoreMenu.Enabled = !show;
            HideMenu.Enabled = show;
            SetParent(processHandle, WinDesktop);

            if (show)
                MaximizeConsoleWindow();
            else
                MinimizeConsoleWindow();

        }
        public static void MinimizeClick(object sender, EventArgs e) => ResizeWindow(false);
        public static void MaximizeClick(object sender, EventArgs e) => ResizeWindow(true);
        public static IntPtr processHandle;
        public static IntPtr WinShell;
        public static IntPtr WinDesktop;
        public static NotifyIcon notifyIcon;
        public static MenuItem HideMenu = new MenuItem("Hide", new EventHandler(MinimizeClick));
        public static MenuItem RestoreMenu = new MenuItem("Restore", new EventHandler(MaximizeClick));
        public void CleanExit(object sender, EventArgs e)
        {
            notifyIcon.Visible = false;
            this.Close();
        }

If you are having problems getting this to work, check that you have 如果您在使用此功能时遇到问题,请检查您的情况

this.Resize += new System.EventHandler(this.Form1_Resize);

in the fom1.designer.cs 在fom1.designer.cs中

In the constructor of the Form: 在表单的构造函数中:

this.Resize += new EventHandler(MainForm_Minimize);

Then use this Event Handler method: 然后使用此事件处理程序方法:

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

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

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