232

WPF アプリケーションをデスクトップの前面に表示するにはどうすればよいですか? これまでのところ、私は試しました:

SwitchToThisWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle, true);

SetWindowPos(new WindowInteropHelper(Application.Current.MainWindow).Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);

どれもジョブを実行していません (Marshal.GetLastWin32Error()これらの操作が正常に完了したことを示しており、各定義の P/Invoke 属性には がありますSetLastError=true)。

新しい空の WPF アプリケーションを作成SwitchToThisWindowし、タイマーを使用して呼び出すと、期待どおりに機能するため、元のケースで機能しない理由がわかりません。

編集:グローバルホットキーと組み合わせてこれを行っています。

4

19 に答える 19

334
myWindow.Activate();

ウィンドウを最前面に移動してアクティブ化しようとします。

私が誤解していて、常に最上位の動作が必要でない限り、それでうまくいくはずです。その場合、次のことが必要です。

myWindow.TopMost = true;
于 2008-12-20T20:32:51.970 に答える
186

ウィンドウを一番上に表示する解決策を見つけましたが、通常のウィンドウとして動作します。

if (!Window.IsVisible)
{
    Window.Show();
}

if (Window.WindowState == WindowState.Minimized)
{
    Window.WindowState = WindowState.Normal;
}

Window.Activate();
Window.Topmost = true;  // important
Window.Topmost = false; // important
Window.Focus();         // important
于 2011-01-28T18:39:46.390 に答える
38

ウィンドウを最初にロードするときに前面に表示する必要がある場合は、次を使用する必要があります。

private void Window_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
}

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}

または、メソッドをオーバーライドして:

protected override void OnContentRendered(EventArgs e)
{
    base.OnContentRendered(e);
    Topmost = false;
}

protected override void OnInitialized(EventArgs e)
{
    base.OnInitialized(e);
    Topmost = true;
}
于 2009-10-14T09:29:00.813 に答える
27

この質問がかなり古いことは知っていますが、この正確なシナリオに出くわしたばかりで、実装したソリューションを共有したいと思いました。

このページのコメントで述べたように、提案されたソリューションのいくつかは XP では機能しないため、私のシナリオではサポートする必要があります。@Matthew Xavier による、一般的にこれは悪い UX プラクティスであるという意見には同意しますが、完全に妥当な UX である場合もあります。

WPF ウィンドウを一番上に表示するソリューションは、実際には、グローバル ホットキーを提供するために使用しているのと同じコードによって提供されました。Joseph Cooney によるブログ記事には、元のコードを含む彼のコード サンプルへのリンクが含まれています。

コードを少し整理して修正し、System.Windows.Window の拡張メソッドとして実装しました。XP 32 ビットと Win7 64 ビットでこれをテストしましたが、どちらも正しく動作します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace System.Windows
{
    public static class SystemWindows
    {
        #region Constants

        const UInt32 SWP_NOSIZE = 0x0001;
        const UInt32 SWP_NOMOVE = 0x0002;
        const UInt32 SWP_SHOWWINDOW = 0x0040;

        #endregion

        /// <summary>
        /// Activate a window from anywhere by attaching to the foreground window
        /// </summary>
        public static void GlobalActivate(this Window w)
        {
            //Get the process ID for this window's thread
            var interopHelper = new WindowInteropHelper(w);
            var thisWindowThreadId = GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);

            //Get the process ID for the foreground window's thread
            var currentForegroundWindow = GetForegroundWindow();
            var currentForegroundWindowThreadId = GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);

            //Attach this window's thread to the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            //Set the window position
            SetWindowPos(interopHelper.Handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

            //Detach this window's thread from the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            //Show and activate the window
            if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
            w.Show();
            w.Activate();
        }

        #region Imports

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

        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        [DllImport("user32.dll")]
        private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        #endregion
    }
}

このコードが、この問題に遭遇した他の人に役立つことを願っています。

于 2012-07-19T01:56:55.567 に答える
23

これをすばやくコピーして貼り付けるには -
このクラスのDoOnProcessメソッドを使用して、プロセスのメイン ウィンドウを前面に移動します (ただし、他のウィンドウからフォーカスを盗むことはできません)。

public class MoveToForeground
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);

    const int SWP_NOMOVE        = 0x0002;
    const int SWP_NOSIZE        = 0x0001;            
    const int SWP_SHOWWINDOW    = 0x0040;
    const int SWP_NOACTIVATE    = 0x0010;
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

    public static void DoOnProcess(string processName)
    {
        var allProcs = Process.GetProcessesByName(processName);
        if (allProcs.Length > 0)
        {
            Process proc = allProcs[0];
            int hWnd = FindWindow(null, proc.MainWindowTitle.ToString());
            // Change behavior by settings the wFlags params. See http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
            SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
        }
    }
}

HTH

于 2011-09-26T18:47:08.900 に答える
13

ユーザーが別のアプリケーションと対話している場合、自分のアプリケーションを前面に表示できない場合があります。原則として、プロセスは、そのプロセスがすでにフォアグラウンド プロセスである場合にのみ、フォアグラウンド ウィンドウを設定することを期待できます。(Microsoft はSetForegroundWindow() MSDN エントリの制限事項を文書化しています。) これは次の理由によるものです。

  1. ユーザーはフォアグラウンドを「所有」します。たとえば、ユーザーが入力している間に別のプログラムがフォアグラウンドを盗んだ場合、少なくともワークフローを中断し、意図しない結果を引き起こす可能性があると、非常に厄介です。 .
  2. 2 つのプログラムのそれぞれが、そのウィンドウがフォアグラウンドかどうかを確認し、フォアグラウンドでない場合はフォアグラウンドに設定しようとしているとします。2 番目のプログラムが実行されるとすぐに、タスクが切り替わるたびにフォアグラウンドが 2 つの間を行き来するため、コンピューターは役に立たなくなります。
于 2009-01-06T04:43:34.283 に答える
8

これは遅い答えであることを知っています。研究者にとっては役立つかもしれません

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }
于 2014-12-11T10:17:53.263 に答える
7

Shell オブジェクトを介して Access アプリケーションから呼び出される WPF アプリケーションでも同様の問題が発生しました。

私の解決策は次のとおりです-x86ターゲットにコンパイルされたアプリを使用して、XPおよびWin7 x64で動作します。

Altタブをシミュレートするよりも、これを実行したいです。

void Window_Loaded(object sender, RoutedEventArgs e)
{
    // make sure the window is normal or maximised
    // this was the core of the problem for me;
    // even though the default was "Normal", starting it via shell minimised it
    this.WindowState = WindowState.Normal;

    // only required for some scenarios
    this.Activate();
}
于 2010-10-07T23:41:01.793 に答える
5

さて、これは非常にホットなトピックなので...これが私にとってうまくいくものです. ウィンドウが表示されない場合、Activate() でエラーが発生するため、この方法で実行しないとエラーが発生します。

Xaml:

<Window .... 
        Topmost="True" 
        .... 
        ContentRendered="mainWindow_ContentRendered"> .... </Window>

コードビハインド:

private void mainWindow_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
    this.Activate();
    _UsernameTextBox.Focus();
}

これが、ウィンドウを一番上に表示する唯一の方法でした。次に、マウスでフォーカスを設定しなくてもボックスに入力できるようにアクティブにします。control.Focus() は、ウィンドウが Active() でない限り機能しません。

于 2012-08-16T15:51:08.897 に答える
3

さて、私は回避策を見つけました。ホットキーの実装に使用されるキーボードフックから電話をかけています。一時停止してBackgroundWorkerに入れると、呼び出しは期待どおりに機能します。応急修理ですが、なぜ元々機能していなかったのかわかりません。

void hotkey_execute()
{
    IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
    BackgroundWorker bg = new BackgroundWorker();
    bg.DoWork += new DoWorkEventHandler(delegate
        {
            Thread.Sleep(10);
            SwitchToThisWindow(handle, true);
        });
    bg.RunWorkerAsync();
}
于 2008-11-03T01:40:26.450 に答える
2

現在開いているウィンドウを表示するには、これらの DLL をインポートします。

public partial class Form1 : Form
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);
    [DllImportAttribute("User32.dll")]
    private static extern int SetForegroundWindow(int hWnd);

とプログラムで指定されたタイトルのアプリを検索します(最初の文字なしでタイトルを書いてください(インデックス> 0))

  foreach (Process proc in Process.GetProcesses())
                {
                    tx = proc.MainWindowTitle.ToString();
                    if (tx.IndexOf("Title of Your app WITHOUT FIRST LETTER") > 0)
                    {
                        tx = proc.MainWindowTitle;
                        hWnd = proc.Handle.ToInt32(); break;
                    }
                }
                hWnd = FindWindow(null, tx);
                if (hWnd > 0)
                {
                    SetForegroundWindow(hWnd);
                }
于 2010-11-11T17:32:59.883 に答える
1

問題は、フックからコードを呼び出すスレッドがランタイムによって初期化されていないため、ランタイムメソッドの呼び出しが機能しないことである可能性があります。

おそらく、Invokeを実行してコードをUIスレッドにマーシャリングし、ウィンドウを前面に表示するコードを呼び出すことができます。

于 2009-02-27T21:03:31.177 に答える