3

C#/.NET アプリがあり、次の動作を実装したいと考えています。

ポップアップメニューがあります。ユーザーがポップアップ メニュー以外のアプリケーションの何かをクリックするたびに、ポップアップ メニューを閉じる必要があります

ただし、ユーザーがアプリケーションにいないときはいつでも、何も起こりたくありません。

LostFocus イベントを通じてこれを管理しようとしていますが、アプリケーションがアクティブ ウィンドウであるかどうかを判断するのに問題があります。コードは次のようになります。

    private void Button_LostFocus(object sender, System.EventArgs e)
    {
        if (InActiveWindow()) {
           CloseMenu()
        }
        else {
           // not in active window, do nothing
        }
    }

私が知る必要があるのは、InActiveWindow() メソッドを実装する方法です。

4

3 に答える 3

4

GetForegroundWindow()にP/Invoke し、返された HWND をアプリケーションの form.Handle プロパティと比較できます。

ハンドルを取得したら、 GetAncestor()をP/Invokeしてルート オーナー ウィンドウを取得することもできます。これがアプリケーション内にある場合、これはアプリケーションのメインの起動ウィンドウのハンドルである必要があります。

于 2009-05-21T16:02:58.527 に答える
2

プロジェクトに取り組んでいるときにあなたの質問に出くわし、 Reed Copsey の回答に基づいて、うまく機能しているように見えるこの簡単なコードを書きました。

コードは次のとおりです。

Public Class Form1
    '''<summary>
    '''Returns a handle to the foreground window.
    '''</summary>
    <Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function GetForegroundWindow() As IntPtr
    End Function

    '''<summary>
    '''Gets a value indicating whether this instance is foreground window.
    '''</summary>
    '''<value>
    '''<c>true</c> if this is the foreground window; otherwise, <c>false</c>.
    '''</value>
    Private ReadOnly Property IsForegroundWindow As Boolean
        Get
            Dim foreWnd = GetForegroundWindow()
            Return ((From f In Me.MdiChildren Select f.Handle).Union(
                    From f In Me.OwnedForms Select f.Handle).Union(
                    {Me.Handle})).Contains(foreWnd)
        End Get
    End Property
End Class

締め切りが 2 日以内のプロジェクトに取り組んでいるため、C# に変換する時間があまりありませんでしたが、すぐに変換できると思います。

VB.NET コードの C# バージョンを次に示します。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    ///<summary>Gets a value indicating whether this instance is foreground window.</summary>
    ///<value><c>true</c> if this is the foreground window; otherwise, <c>false</c>.</value>
    private bool IsForegroundWindow
    {
        get
        {
            var foreWnd = GetForegroundWindow();
            return ((from f in this.MdiChildren select f.Handle)
                .Union(from f in this.OwnedForms select f.Handle)
                .Union(new IntPtr[] { this.Handle })).Contains(foreWnd);
        }
    }
}
于 2011-01-01T12:12:40.843 に答える
1

これが難しい最大の理由は、メイン フォームが非アクティブ化される前にポップアップがフォーカスを失うためであると思われます。そのため、アクティブなウィンドウは、このイベントの時点でアプリケーション内に常に存在します。本当に、イベントが終わった後もアクティブなウィンドウであるかどうかを知りたいです。

LostFocusポップアップがフォーカスを失っていることを記憶し、それを閉じる必要があるという事実を脇に置いて、アプリケーションのメインフォームの場合またはDeactivateイベントで、閉じる必要があることを通知するメモをキャンセルする、ある種のスキームを設定できます。それ; 問題は、いつそのメモを処理するかです。

少なくともポップアップがメインフォームの直接の子である場合(あなたの場合はそうであると思われます) 、メインフォームのイベントFocusまたはClickイベントをフックしてポップアップを閉じる方が簡単かもしれないと考えています開いている場合 (おそらく、ICloseOnLostFocus インターフェイスを実装する子フォームのリストをスキャンして、ポップアップが決定に参加し、必要なその他の処理を実行できるようにします)。

これらすべてのイベントが実際に何を意味し、それらが相互にどのように順序付けられているかを説明するより良いドキュメントを知っていればよかったのですが、MSDN には、それらの説明について多くの要望が残されています。

于 2009-06-24T01:26:39.873 に答える