はじめに
Windows用の常駐型アプリを標ぼうするため、タスクトレイ(通知領域)にアイコンを表示させ
- 「起動時には自フォームを非表示」
- 「タスクトレイ(通知領域)アイコンをダブルクリックしたら、タスクトレイの近くに自フォームを表示」
を実装してみます。
うまくいかない例
「起動時には非表示」のため、フォームの Visible プロパティ初期値を False に設定する。
これは残念ながら最初からフォームが表示されてしまいます。
「起動時には非表示」のため、フォームの WindowState プロパティ初期値を Minimized にしてかつ ShowInTaskbar プロパティを False に設定し、タスクトレイアイコンをダブルクリックしたら WindowState プロパティを Normal にすればよい。
起動時の非表示化は成功しますが、ダブルクリックイベントで表示させるときに、変な場所からとび出てきて表示されて、格好悪いです。
コードと説明
課題を実現してみたコードです。Visual Studio 2017 (15.8.1)から、SampleAppという名前のプロジェクトを「Windowsフォームアプリケーション(.NET Framework : C#)」(.NET Framework 4.5.2) で作成しました。初期作成される Form1 に、NotifyIcon(notifyIcon1:タスクトレイアイコン)と、Button(buttonExit:アプリを終了させるボタン)を、それぞれ配置しています。
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace SampleApp
{
public partial class Form1 : Form
{
private bool _initialized = false;
public Form1()
{
InitializeComponent();
// デザイナで初期設定してもOK
this.MaximizeBox = false;
this.MinimizeBox = false;
this.StartPosition = FormStartPosition.Manual;
}
protected override void SetVisibleCore(bool value)
{
// コントロールの表示状態を強制:初回は非表示にする
base.SetVisibleCore(_initialized && value);
_initialized = true;
}
protected override void OnClosing(CancelEventArgs e)
{
// フォームを閉じる操作をされた
//base.OnClosing(e);
this.Visible = false;
e.Cancel = true;
}
private void buttonExit_Click(object sender, EventArgs e)
{
// 終了ボタン押下
Application.Exit();
}
private void notifyIcon1_DoubleClick(object sender, EventArgs e)
{
// タスクトレイ(通知領域)のアイコンダブルクリック
SetFormLocation();
this.Visible = true;
}
// ここが今回のキモ!!
private void SetFormLocation()
{
var wa = Screen.PrimaryScreen.WorkingArea;
if (0 < wa.Left)
{
// タスクバーは左
this.Location = new System.Drawing.Point(wa.Left, wa.Bottom - this.Height);
}
else if (0 < wa.Top)
{
// タスクバーは上
this.Location = new System.Drawing.Point(wa.Right - this.Width, wa.Top);
}
else
{
// タスクバーは右か下
this.Location = new System.Drawing.Point(wa.Right - this.Width, wa.Bottom - this.Height);
}
}
}
}
初期表示を非表示にする
フォームの SetVisibleCore 仮想メソッドをオーバーライドして、コントロールの表示状態を強制させることができます。Visible (Visibility) の Setter メソッドのさらに中核ということで SetVisibleCore というメソッド名なのかしら...
このプログラムでは、初回の呼び出し時のみ Visible = False を強制して、初期表示を非表示にさせています。
タスクトレイアイコンダブルクリック時に、通知領域に寄せて(通知領域に近いデスクトップ内のエッジの位置に)フォームを表示する
通知領域(タスクトレイ)の座標やタスクバーの位置を得る方法があればズバリかもしれませんが、当方残念ながら存じません(ご存知の方、ぜひ教えてください!)
そこで代替手段、プライマリスクリーンの作業領域座標からタスクバーの位置、ひいては通知領域の位置を推測します。Form.Screen プロパティのPrimaryScreen.WorkingArea プロパティには、プライマリスクリーンの作業領域座標(タスクバーなどを除いたデスクトップ座標)が入っています。
作業領域座標の上端が0ではない場合は、上側に作業領域ではない領域(タスクバーなど)があると考えます(左端の場合も同様)
タスクバーを自動で隠す設定にされていてタスクバーが隠れている状態だと、このスクリーン座標と作業領域座標とは一致してしまって検出できなくなるのですが、「通知領域アイコンがダブルクリック」されるときにはタスクバーは必ず表示されているので、そこのところは気にしなくて済みそうです。
おわりに
もっとエレガントな方法がありましたら、ぜひ教えてください!