1

I have a very typical hackish solution for minimizing to system tray in C#:

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

private void systemTrayIconMouseDoubleClick(object sender, MouseEventArgs e) {
    systemTrayIcon.Visible = false;
    this.Show();
    this.WindowState = FormWindowState.Normal;  
}

Ideally, I want my application to disappear/reappear when minimizing to or reopening from the system tray. Minimizing to the system tray works as expected -- the window disappears with no delay and there appears a new tray icon.

Double-clicking on the icon, however, has some very strange effects. The window undergoes a resize animation to its position -- the window appears to fly in from a completely random corner of the screen.

I don't want that. I just want Minimize > -Poof- Disappear and Double-click > -Poof- Appear with no animations or delays or anything of that sort.

Why does this code have an animation? If I call Form.Show() in any other context, the window automatically appears like I want, but when called from a NotifyIcon, it acts strangely. I thought it might be the WindowState = FormWindowState.Normal line, but if I remove that, the window isn't brought to the foreground.

Edit: This problem seems to be OS and theme dependent. The problem doesn't appear to exist in Windows XP, but it's hard to tell because my virtual machine is a little laggy. In Windows 7 Aero, the abitrary-offscreen position problem occurs. In Windows 7 Basic/Classic, it minimizes to the task bar, and reappears from its old position in the taskbar (as if it was actually minimized to the task bar, not the system tray). I haven't tested on Vista. Any tips?

Corey
  • 1,177
  • 4
  • 16
  • 24

4 Answers4

2

Did you try reordering to put WindowState = FormWindowState.Normal before Show()? I believe the animation you are seeing is the standard window restore animation. Since you are calling Show() before restoring your window, it gets an off-screen position.

Edit: I see your issue now - I looked at it for a second or so, and even tried an IMessageFilter, but for some reason couldn't trap WM_SYSCOMMAND when minimizing (although it fires on restoring).

The one easy thing you could do is live with the minimize animation, though - in your resize handler, just before the Hide() call, set WindowState to Normal. You'll see the minimize animation, but not the maximize (which on most platforms is much less noticeable).

Philip Rieck
  • 32,368
  • 11
  • 87
  • 99
  • If I do that, then the window is never shown at all. It appears in the task bar, but clicking that to bring the window up just re-minimizes it. – Corey Nov 22 '10 at 22:53
  • I added a little bit of extra information to my post if that helps at all. – Corey Nov 22 '10 at 22:58
  • Thanks for the tip, that effect is a little more desirable. The problem now is that changing the WindowState re-calls MainFormResize, and I guess something internal invoked from MainFormResize that I can't control tries to display the Window when WindowState.Normal is called. What that leaves me with is the form minimizes, then reappears for a split millisecond (with controls blacked out because the system cannot load the form that fast) and then hides it. It's quite strange. – Corey Nov 23 '10 at 01:12
  • @Corey You can block that by putting a guard boolean in the OnResize override, and not calling the base implementation - but it will look slightly odd any way you slice it. The "real" way to do it is outlined here - http://stackoverflow.com/questions/46918/whats-the-proper-way-to-minimize-to-tray-a-c-winforms-app. But notice that that includes animations. Otherwise you're stuck with using P/Invoke and an IMessageFilter - I'll look at that tomorrow if you're still stuck (no computer now) – Philip Rieck Nov 23 '10 at 01:27
0

At least it is possible to have the animation originate from where it should - you have to move the minimized window near the tray notification area: see my hack here

Community
  • 1
  • 1
maf-soft
  • 2,335
  • 3
  • 26
  • 49
0

If you need to hide the window when the program runs, your best bet is to create a class that derives from ApplicationContext and shows the NotifyIcon. You then use this class instead of form in the Application.Run.

class TaskTray : ApplicationContext
{
    private NotifyIcon _Icon;
    public TaskTray()
    {
       _Icon = new NotifyIcon();
       //...
    )
}
static void Main()
{
    Application.Run(new TaskTray());
}
Joel Lucsy
  • 8,520
  • 1
  • 29
  • 35
0

Well, this is an old question, but it's the first result I hit when googling, so I'll share my findings, maybe someone could find this useful.

My application starts with no window showing on the desktop, only a tray icon. The main window can be shown by double-clicking on the tray icon, and closing the window will hide it to the tray icon again.

When my application is hidden, the taskbar icon is hidden as well. However, when it's shown, I have the taskbar icon shown as well, so it can be switched between other windows.

It works as intended. However, I can't help but noticing the animation when showing the window feels very strange and jerky, and it's bugging me a lot. After some digging around, I found the animation behavior is affected by ShowInTaskbar property of the form.

        private void ShowMainWindow(object sender, EventArgs e)
        {
            //ShowInTaskbar = true; // smooth animation
            Show();
            //ShowInTaskbar = true; // jerky animation
        }

Without the ShowInTaskbar = true; line, the window would appear instantly without any animation. Putting the line below Show(); results in the "jerky" animation. Putting the line above Show() gives a smooth fading-in animation and that's the one I choose in the end.

RadarNyan
  • 306
  • 1
  • 2
  • 12