2016-04-22 1 views
0

Я просто хочу заменить кнопку панели задач моего приложения winforms значком уведомлений в трее. Это означает, что если пользователь щелкнул левой кнопкой мыши по значку, форма должна быть активирована, если она не была сфокусирована, иначе сведена к минимуму или скрыта.Правильный способ активации моего MainForm из NotifyIcon, если он не был сфокусирован уже

Я прочитал много статей о правильном использовании NotifyIcon, и, похоже, я должен принять хакерское решение. Итак, что самое подходящее?

Я получил его в основном для запуска, но теперь я застрял в обнаружении, если моя форма уже активна, потому что при нажатии на значок форма теряет фокус, поэтому я не могу проверить свойство Focused.

Следующий код еще не решил это, поэтому, если форма была просто скрыта другими окнами, вам нужно нажать 2 раза, потому что первый клик сводит к минимуму.

Как его можно улучшить?

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

    private void notifyIcon_MouseDown(object sender, MouseEventArgs e) 
    { 
     if (e.Button == MouseButtons.Left) 
      if (WindowState == FormWindowState.Minimized) { 
       WindowState = FormWindowState.Normal; 
       Show(); 
       Activate(); 
      } 
      else { 
       Hide(); 
       WindowState = FormWindowState.Minimized; 
      } 
    } 

(я тоже не понимаю, почему Click событие срабатывает на правой кнопкой мыши, который уже открывает контекстное меню, в моем случае ...)

(И, конечно, было бы неплохо имеют правильную минимизацию анимации, но есть и другие вопросы здесь, где это не было действительно решено)

(Я знаю, что я сказал Focused, но если форма уже была полностью видимой (но, возможно, не сфокусированной), а пользователь щелкает значок в трее, он, скорее всего, захочет его скрыть)

+2

Вам нужно будет прибегнуть к хакам с момента, когда вы нажмете на NotifyIcon, ваша форма будет деактивирована. Множество хаков, пытающихся запустить таймер в событии MouseMove и попытаться создать событие MouseLeave, связанное с этим значком, но ни один из них не является надежным, потому что окна не предоставляют границы прямоугольника вашего значка. – LarsTech

+0

@LarsTech, тогда, может быть, лучше начать таймер при дезактивации формы ... Но мне это не понравится. –

ответ

1

@ LarsTech предложил взломать таймер, и это работает, спасибо, но я все еще надеюсь на лучшее решение или улучшения.

Может быть интересно: я также решил часть проблемы с анимацией - когда нет кнопки на панели задач, анимация начинается с того, где находится свернутая форма. Вы можете сделать это видимым, вызвав Show() после минимизации. Он находится в левом нижнем углу экрана, и его невозможно переместить, установив, например, свойство Left. Поэтому я использовал winapi напрямую, и он работает! К сожалению, только для анимации восстановления, потому что я не знаю, как установить минимизированную позицию перед минимизацией. Hide() в любом случае отключает анимацию, поэтому мне пришлось бы ее задерживать ...

Это все так неутешительно! Почему нет хорошего решения? Я никогда не могу быть уверен, что он будет работать в каждом сценарии. Например, на одной машине он работал хорошо с таймером 100 мс, но по другому мне понадобилось 200 мс. Поэтому я предлагаю иметь минимум 500 мс.

[DllImport("user32.dll", SetLastError = true)] 
static extern bool MoveWindow(IntPtr hWnd, 
    int X, int Y, int nWidth, int nHeight, bool bRepaint); 

private void FormMain_Resize(object sender, EventArgs e) 
{ 
    if (!ShowInTaskbar && WindowState == FormWindowState.Minimized) { 
     Hide(); 
     //Move the invisible minimized window near the tray notification area 
     if (!MoveWindow(Handle, Screen.PrimaryScreen.WorkingArea.Left 
       + Screen.PrimaryScreen.WorkingArea.Width - Width - 100, 
       Top, Width, Height, false)) 
      throw new Win32Exception(); 
    } 
} 

private void notifyIcon_MouseDown(object sender, MouseEventArgs e) 
{ 
    if (e.Button == MouseButtons.Left) 
     if (WindowState == FormWindowState.Minimized || !timer.Enabled) { 
      Show(); 
      WindowState = FormWindowState.Normal; 
      Activate(); 
     } 
     else { 
      WindowState = FormWindowState.Minimized; 
      //FormMain_Resize will be called after this 
     } 
} 

private void FormMain_Deactivate(object sender, EventArgs e) 
{ 
    timer.Start(); 
} 

private void timer_Tick(object sender, EventArgs e) 
{ 
    timer.Stop(); 
} 

//other free goodies not mentioned before... 

private void taskbarToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    ShowInTaskbar = !ShowInTaskbar; 
    taskbarToolStripMenuItem.Checked = ShowInTaskbar; 
} 

private void priorityToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    //Set the process priority from ToolStripMenuItem.Tag 
    //Normal = 32, Idle = 64, High = 128, BelowNormal = 16384, AboveNormal = 32768 
    Process.GetCurrentProcess().PriorityClass 
     = (ProcessPriorityClass)int.Parse((sender as ToolStripMenuItem).Tag.ToString()); 
    foreach (ToolStripMenuItem item in contextMenuStrip.Items) 
     if (item.Tag != null) 
      item.Checked = item.Equals(sender); 
} 

private void exitToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    Close(); 
} 
Смежные вопросы