views:

460

answers:

5

Hello! I have a program which only needs a NotifyIcon to work as intended. So I've been trying to get the main form to hide when the program starts.

In frmMain_Load, I tried both

this.Hide();
this.Visible = false;

without success.

They work in other methods, like in the NotifyIcon_MouseClick-method, but I want it to hide at Load.

I saw in another question here at SO where Matias suggested this:

BeginInvoke(new MethodInvoker(delegate
{
    Hide();
}));

This works, but when I launch the program I can see the form flashing real fast. It's better than nothing, but I wonder if there is any better solution to this.

Thanks.

+3  A: 

Don't call Show or ShowDialog on your form, you can have your Application.Run target a custom class that then instantiates a form and doesn't show or creates a NotifyIcon instance and handles everything from there.

Quintin Robinson
You can also just call Application.Run() without any parameters.When your application is finished call Application.Exit();
VBNight
This won't work if you need to get some event notifications, such as power events, etc. where you really need an (invisible) form to get them.
Pierre
Thanks for your reply. Do I have to create my own custom form class or could I just remove the Show()-line somewhere? If I have to create my own custom class, how do I do that? I've been looking around in the code but I don't find anything interesting.
sippa
Well you would just create a basic class instead of telling the application to block on a form. Inside of the object you can handle instantiating your Form and handling your NotifyIcon, it's alot like VBNight had suggested in his comment. There would be nothing special about your class.
Quintin Robinson
I added an example below about what I'm talking about (Comment wouldn't format it correctly)
VBNight
Thanks for your help! VBNight's example works like I wanted to.
sippa
Good Deal, glad you got it working and without any hackslash form hiding magic!
Quintin Robinson
+2  A: 

There is an easy way, if your program has the default Visual Studio generated Program.cs file:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles ();
    Application.SetCompatibleTextRenderingDefault (false);
    Application.Run (new MainForm ());
}

the simple fact of calling Run will, indeed make the form visible. Try doing the following in the properties of your form:

  1. Set WindowState to Minimized
  2. Set ShowInTaskbar to false

This should do the trick!

Pierre
Thanks for your reply! I forgot to mention that I already tried this way. It worked partially, but I could see the form title bar in the bottom left corner, so I want to do it some other way. Thanks anyway!
sippa
A: 

You can also put this.hide = true in the form_shown event. I believe that event is fired once only and after the load event. You might see alittle flicker though if your form has a lot of controls and/or the computer is slow.

masfenix
I just tried this, and while it works you can still see the form flashing real quick. I'd rather fix it totally, but thanks for your suggestion!
sippa
+1  A: 

If your program doesn't require a form to run, then the best method is to not have a form at all. Setup your NotifyIcon in the Program code, and enter a loop until you want to exit the program by setting some value, or calling some method. In this example setting UserExitCalled to true (Program.UserExitCalled = true) will cause the program to quit. Here is a brief example:

static class Program {
    internal static Boolean UserExitCalled;

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

        // Setup your tray icon here

        while (!UserExitCalled) {
            Application.DoEvents(); // Process windows messages
            Thread.Sleep(1);
        }

        return;
    }
}

Here the full program class from one of my system tray applications as a working example.

// *********************************************************************
// [DCOM Productions .NET]
// [DPDN], [Visual Studio Launcher]
//
//   THIS FILE IS PROVIDED "AS-IS" WITHOUT ANY WARRANTY OF ANY KIND. ANY
//   MODIFICATIONS TO THIS FILE IN ANY WAY ARE YOUR SOLE RESPONSIBILITY.
//
// [Copyright (C) DCOM Productions .NET  All rights reserved.]
// *********************************************************************

namespace VisualStudioLauncher
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Forms;
    using System.Threading;
    using VisualStudioLauncher.Common.Objects;
    using VisualStudioLauncher.Forms;
    using System.Drawing;
    using VisualStudioLauncher.Common.Data;
    using System.IO;
static class Program
{
    #region Properties

    private static ProjectLocationList m_ProjectLocationList;
    /// <summary>
    /// Gets or Sets the ProjectsLocationList
    /// </summary>
    public static ProjectLocationList ProjectLocationList
    {
        get
        {
            return m_ProjectLocationList;
        }

        set
        {
            m_ProjectLocationList = value;
        }
    }

    private static ShellProcessList m_ShellProcessList = null;
    /// <summary>
    /// Gets or Sets the ShellProcessList
    /// </summary>
    public static ShellProcessList ShellProcessList
    {
        get
        {
            return m_ShellProcessList;
        }

        set
        {
            m_ShellProcessList = value;
        }
    }

    private static NotifyIcon m_TrayIcon;
    /// <summary>
    /// Gets the programs tray application.
    /// </summary>
    public static NotifyIcon TrayIcon
    {
        get
        {
            return m_TrayIcon;
        }
    }

    private static bool m_UserExitCalled;
    /// <summary>
    /// Gets a value indicating whether the user has called for an Application.Exit
    /// </summary>
    public static bool UserExitCalled
    {
        get
        {
            return m_UserExitCalled;
        }

        set
        {
            m_UserExitCalled = value;
        }
    }

    // TODO: Finish implementation, then use this for real.
    private static ApplicationConfiguration m_ApplicationConfiguration = null;
    /// <summary>
    /// Gets the application configuration
    /// </summary>
    public static ApplicationConfiguration ApplicationConfiguration
    {
        get
        {
            if (m_ApplicationConfiguration == null)
                m_ApplicationConfiguration = ApplicationConfiguration.LoadConfigSection(@"./settings.config");

            return m_ApplicationConfiguration;
        }
    }


    #endregion

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        if (args.Length > 0)
        {
            if (args[0].ToLower() == "-rmvptr")
            {
                for (int i = 1; i < args.Length; i++) {
                    try {
                        if (File.Exists(Application.StartupPath + @"\\" + args[i])) {
                            File.Delete(Application.StartupPath + @"\\" + args[i]);
                        }
                    }
                    catch { /* this isn't critical, just convenient */ }
                }
            }
        }

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        SplashForm splashForm = new SplashForm();
        splashForm.Show();

        while (!UserExitCalled)
        {
            Application.DoEvents();
            Thread.Sleep(1);
        }

        if (m_TrayIcon != null)
        {
            m_TrayIcon.Icon = null;
            m_TrayIcon.Visible = false;
            m_TrayIcon.Dispose();

            GC.Collect();
        }
    }

    #region System Tray Management

    public static void SetupTrayIcon()
    {
        m_TrayIcon = new NotifyIcon();
        m_TrayIcon.Text = Resources.UserInterfaceStrings.ApplicationName;
        m_TrayIcon.Visible = false; // This will be set visible when the context menu is generated
        m_TrayIcon.MouseDoubleClick += new MouseEventHandler(m_TrayIcon_MouseDoubleClick);

        if (Orcas.IsInstalled)
        {
            m_TrayIcon.Icon = Orcas.Icon;
        }
        else if (Whidbey.IsInstalled) {
            m_TrayIcon.Icon = Whidbey.Icon;
        }
        else {
            m_TrayIcon.Icon = SystemIcons.Warning;
            m_TrayIcon.Text = "Visual Studio is not installed. VSL cannot run properly.";
        }
    }

    static void m_TrayIcon_MouseDoubleClick(object sender, MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left)
        {
            return;
        }

        SettingsForm settingsForm = new SettingsForm();
        settingsForm.Show();
    }

    #endregion
}

}

David Anderson
Unless you call Application.Run I don't think message loop/pump will be started.
VBNight
You can process messages by calling Application.DoEvents(). Since this is not a complex scenario, he doesn't need to even declare a form, yet alone run the message loop using Application.Run()"If you don't need it in your code, remove it." Especially in production code.
David Anderson
+3  A: 
// In Your Program.cs Convert This
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}

// To This
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Form1 TheForm = new Form1();
    Application.Run();
}

// Call Application.Exit() From Anywhere To Stop Application.Run() Message Pump and Exit Application
VBNight
Thanks! This seems to work like I wanted to :D
sippa