0

私のC#アプリケーションは、タスクバーアイコン(NotifyIcon)と最初は非表示になっているオーバーヘッドウィンドウで構成されています。ユーザーがNotifyIconをクリックしてウィンドウの表示を切り替えられるようにしたい(左、シングルクリック)。また、フォーカスを失うとウィンドウが非表示になります。

これは私がこれまでに持っているものであり、サブクラス化されていSystem.Windows.Forms.Formます:

初期化:

this.ControlBox = false;
this.ShowIcon = false;
this.ShowInTaskbar = false;

// Instance variables: bool allowVisible;
//                     System.Windows.Forms.NotifyIcon notifyIcon;

this.allowVisible = false;
this.notifyIcon = new NotifyIcon();
this.notifyIcon.MouseUp += new MouseEventHandler(NotifyIconClicked);
this.Deactivate += new EventHandler(HideOnEvent);

インスタンスメソッド:

private void NotifyIconClicked(object sender, MouseEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Left)
    {
        if (this.Visible)
            this.Hide();
        else
            this.Show();
    }
}

new public void Show()
{
    this.allowVisible = true;
    this.Visible = true;
    this.Activate();
}

new public void Hide()
{
    this.allowVisible = false;
    this.Visible = false;
}

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

protected override void SetVisibleCore(bool visible)
{
    base.SetVisibleCore(this.allowVisible ? visible : this.allowVisible);
}

アイコンをクリックすると、ウィンドウが表示されます。ただし、もう一度クリックすると、マウスが押されている間は非表示になり、その後、表示にリセットされます。

私の推測では、マウスダウンイベントはウィンドウからフォーカスを奪って消えます。次に、マウスアップイベントがトリガーされ、ウィンドウが非表示になっていることが表示されます。

私の次のアイデアは、マウスダウンイベントでのウィンドウの可視性を読み取ることだったので、3つのイベントをテストし、それらが呼び出されたときにUNIX時間を記録しました。

notifyIcon.MouseDown
notifyIcon.MouseUp
this.LostFocus

結果はかなり奇妙です。ウィンドウが表示されているとしましょう。これは、アイコンをクリックすると発生します。フォーカスロストはすぐに呼び出されます。マウスを離すとすぐに、マウスアップイベントの直前にマウスダウンが呼び出されます。

1312372231 focus lost
1312372235 mouse down
1312372235 mouse up

マウスダウンイベントが遅れるのはなぜですか?
ウィンドウを切り替えるにはどうすればよいですか?

4

1 に答える 1

3

私はこれがあなたのために働くかもしれないと思います。

カーソルが現在トレイ上にあるかどうかを確認するためのメソッドを提供するクラスを含むエキスパート交換ポストを見つけました。

NotifyIcon-MouseOutを検出します

このクラスを使用して、HideOnEventメソッドを次のように変更しました。

    private void HideOnEvent(object sender, EventArgs e)
    {
        if (!WinAPI.GetTrayRectangle().Contains(Cursor.Position))
        {
            this.Hide();
        }
    }

これはあなたが必要なことをするようです。

私は以下のクラスを含めました:

using System.Runtime.InteropServices;
using System.Drawing;

public class WinAPI
{
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;

        public override string ToString()
        {
            return "(" + left + ", " + top + ") --> (" + right + ", " + bottom + ")";
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindow(string strClassName, string strWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);


    public static IntPtr GetTrayHandle()
    {
        IntPtr taskBarHandle = WinAPI.FindWindow("Shell_TrayWnd", null);
        if (!taskBarHandle.Equals(IntPtr.Zero))
        {
            return WinAPI.FindWindowEx(taskBarHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero);
        }
        return IntPtr.Zero;
    }

    public static Rectangle GetTrayRectangle()
    {
        WinAPI.RECT rect;
        WinAPI.GetWindowRect(WinAPI.GetTrayHandle(), out rect);
        return new Rectangle(new Point(rect.left, rect.top), new Size((rect.right - rect.left) + 1, (rect.bottom - rect.top) + 1));
    }
}

これは完璧な解決策ではありませんが、これがお役に立てば幸いです。

于 2011-08-03T13:34:26.773 に答える