[C#] WPF에서 창을 앞으로 가져 오기

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타이머를 사용하여 호출 하면 예상대로 정확하게 작동하므로 원래 사례에서 왜 작동하지 않는지 잘 모르겠습니다.

편집 : 나는 글로벌 핫키와 함께 이것을하고 있습니다.



답변

myWindow.Activate();

창을 전경으로 가져 와서 활성화합니다.

내가 오해하지 않고 항상 맨 위의 동작을 원하지 않는 한 트릭을 수행해야합니다. 이 경우에는 다음을 원합니다.

myWindow.TopMost = true;


답변

창을 맨 위로 가져 오는 솔루션을 찾았지만 일반 창처럼 작동합니다.

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


답변

창을 처음로드 할 때 맨 앞에 있어야하는 경우 다음을 사용해야합니다.

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

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


답변

이것을 빠른 복사-붙여 넣기 방법으로 만들기 –
이 클래스의 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


답변

나는이 질문이 다소 오래되었다는 것을 알고 있지만이 정확한 시나리오를 보았고 구현 한 솔루션을 공유하고 싶었습니다.

이 페이지의 의견에서 언급했듯이 제안 된 여러 솔루션은 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
    }
}

이 코드가이 문제를 겪는 다른 사람들에게 도움이되기를 바랍니다.


답변

사용자가 다른 응용 프로그램과 상호 작용하는 경우 사용자의 응용 프로그램을 맨 앞으로 가져올 수 없습니다. 일반적으로 프로세스는 해당 프로세스가 이미 포 그라운드 프로세스 인 경우에만 포 그라운드 창을 설정할 것으로 예상 할 수 있습니다. (Microsoft는 SetForegroundWindow () MSDN 항목 의 제한 사항을 설명합니다 .) 그 이유는 다음과 같습니다.

  1. 사용자는 포 그라운드를 “소유”합니다. 예를 들어, 사용자가 입력하는 동안 다른 프로그램이 포 그라운드를 훔 쳤을 때 최소한 워크 플로우를 방해하고 한 응용 프로그램의 키 입력이 변경 사항을 알 때까지 위반자가 잘못 해석하여 의도하지 않은 결과를 초래할 수 있습니다. .
  2. 두 프로그램 각각이 해당 창의 창이 전경인지 확인하고 그렇지 않은 경우이를 전경으로 설정하려고 시도한다고 상상해보십시오. 두 번째 프로그램이 실행 되 자마자 모든 작업 스위치에서 포 그라운드가 두 개 사이에서 바운스됨에 따라 컴퓨터가 쓸모 없게됩니다.

답변

나는 이것이 답이 늦다는 것을 알고 있습니다.

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }