.Net에서 창을 항상 맨 위에 유지하는 방법은 무엇입니까?


93

다른 프로그램에서 매크로를 실행하는 C # winforms 앱이 있습니다. 다른 프로그램은 계속해서 창을 띄우고 일반적으로 더 나은 단어가 없기 때문에 상황을 미치게 만듭니다. 프로세스 실행을 중지하는 취소 버튼을 구현하고 싶지만 창이 맨 위에 유지되지 않는 것 같습니다. C #에서 어떻게합니까?

편집 : 나는 TopMost = true를 시도했습니다; ,하지만 다른 프로그램은 계속해서 상단에 자체 창을 표시합니다. n 밀리 초마다 내 창을 맨 위로 보내는 방법이 있습니까?

편집 :이 문제를 해결 한 방법은 두 번 클릭하여 프로세스를 취소하는 시스템 트레이 아이콘을 추가하는 것입니다. 시스템 트레이 아이콘이 가려지지 않습니다. 응답 해 주신 모든 분들께 감사드립니다. 왜 '슈퍼 온탑'창이 없는지에 대한 기사를 읽었습니다. 논리적으로 작동하지 않습니다.


62
예, Form.TopMost를 true로 설정하는 몇 밀리 초마다 타이머를 설정하십시오. 그런 다음 흥미롭게 만들기 위해 "미친"프로그램이로드되면 Mortal Kombat "FIGHT!"의 오디오 클립을 재생합니다. :-P
BFree

2
당신은 당신의 말이 재미 있다고 생각했을 수도 있고, 나쁜 습관을 조롱 할 수도 있다고 생각했을 수도 있습니다. 내 문제는 flowlayoutpanel이있는 양식 위에 떠있는 컨텍스트 메뉴를 만드는 것이 었습니다. flowlayoutpanel은 Activate () 메서드를 호출하는 경우에만 스크롤 할 수 있으며 Focus ()는 특정 상황에서 충분하지 않습니다. 스크롤 할 수 없습니다. 그것은 독점적 인 topmost = true가 있더라도 contextmenu에서 초점을 훔칩니다! 현명한 사람이라면 누구나 Winform 응용 프로그램을 MTAThread 모드에서 실행하고 모든 양식에 자체 스레드를 제공하여 솔루션을 간단하게 만드는 것이
경건한 실천입니다

1
보라, 악마 : pastebin.com/sMJX0Yav 깜박임없이 완벽하게 작동하며 sleep (1)은 심각한 성능 저하를 막기에 충분합니다. 컨텍스트 메뉴에 초점을 맞추는 동안 누가 작업 관리자를 계속 살펴 보나요? 컨텍스트 메뉴가 닫히면 빈 예외 처리기로 실행되어 죽습니다. 하지만 isDisposed 휴식 시간에 빌드 할 수 있습니다.
Traubenfuchs 2014

난 그냥 여기에이 문제에 대한 내 솔루션을 게시 : stackoverflow.com/questions/2546566/...
KFN

@Traubenfuchs 때문에 크로스 스레드 작업 예외로 실패합니다. 작동합니다.
mekb

답변:


171

Form.TopMost 다른 프로그램이 최상위 창을 생성하지 않는 한 작동합니다.

다른 프로세스의 새 최상위 창으로 덮이지 않는 창을 만들 수있는 방법이 없습니다. Raymond Chen은 이유를 설명했습니다 .


10
다른 완전한 초보자가 2016 년 이후에 이것을 본다면, 시도하십시오Form.ActiveForm.TopMost
Devil 's Advocate

1
@ScottBeeson : 이것은 좋습니다. 이 테크노 역동적 인 세계에서는 업데이트 된 정보가 매우 필요합니다. 감사:).
하기 Sandeep Kushwah

47

WinForms 응용 프로그램을 "Always on Top"으로 만들려고했지만 "TopMost"를 설정해도 아무런 효과가 없었습니다. WinAmp가이 작업을 수행하기 때문에 가능하다는 것을 알고있었습니다 (다른 여러 응용 프로그램과 함께).

내가 한 것은 "user32.dll"을 호출하는 것이 었습니다. 나는 그렇게하는 것에 대해 아무런 불만이 없었고 훌륭하게 작동합니다. 어쨌든 옵션입니다.

먼저 다음 네임 스페이스를 가져옵니다.

using System.Runtime.InteropServices;

클래스 선언에 몇 가지 변수를 추가합니다.

private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

user32.dll 함수에 대한 프로토 타입을 추가합니다.

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

그런 다음 코드에서 (Form_Load ()에 호출을 추가했습니다) 호출을 추가하십시오.

SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);

도움이 되었기를 바랍니다. 참고


2
이것은 WinForms 응용 프로그램뿐만 아니라 콘솔 창 에서도 작동합니다 . 좋은 발견!
rojo

좋습니다.이게 작동하는지 확인할 수 있습니다. 하지만 어떻게하면 최고가되지 않도록 다시 바꿀 수 있을까요? 공유 할 수있는 HWND_BOTTOMMOST 플래그가 있습니까?
Mark

이 최상위 능력과 기본 동작 사이를 바꾸고 싶다면 좋은 질문입니다 (예 : 창 동작에 대해 "항상 위에"체크 박스가 있습니다). 적절한 플래그를 사용하면 가능할 것이라고 생각합니다. 기본 창 동작을 설명하는 올바른 플래그 (예 : SWP_DEFAULT = 0x0003)가있는 경우 이러한 플래그를 사용하여 "SetWindowPos ()"를 다시 호출 할 수 있습니다. 확실하지 않습니다. 나는 그것을 조사하지 않았습니다. 당신이 그렇게한다면 행운을 빕니다. 누군가가 있다면 여기에 추가하십시오!
clamum apr

이것은 평소와 같이 전체 화면 게임 모드에서 작동하지 않습니다
Sajitha Rathnayake

2
@Mark 예, HWND_NOTOPMOST (= -2) 플래그가 있습니다. docs.microsoft.com/en-us/windows/win32/api/winuser/…
Kevin

23

"미쳐가는 것"이 ​​각 창이 다른 창에서 계속 초점을 훔친다는 의미라면 TopMost는 문제를 해결하지 못할 것입니다.

대신 다음을 시도하십시오.

CalledForm.Owner = CallerForm;
CalledForm.Show();

이것은 초점을 훔치지 않고 '아이'형태를 ​​보여줄 것입니다. 부모가 활성화되었거나 포커스가있는 경우에도 자식 양식은 부모 위에 유지됩니다. 이 코드는 소유자 양식 내에서 자식 양식의 인스턴스를 만든 경우에만 쉽게 작동합니다. 그렇지 않으면 API를 사용하여 소유자를 설정해야 할 수 있습니다.


1
이걸 정확히 사용해 주셔서 감사합니다. 완벽하게 작동했습니다!
AvetisG 2015-06-15

1
감사합니다 .. 내가 찾고 정확히 무엇을위한
사 미라 Kumarasingha

CalledForm.Owner자체 ( CalledForm)로 설정 하면 다음과 같은 오류가 발생합니다 System.ArgumentException. '순환 제어 참조가 만들어졌습니다. 컨트롤은 자신이 소유하거나 부모가 될 수 없습니다. '
mekb

2
그렇기 때문에 CalledForm 대신 CallerForm을 사용합니다. :)
Jesper

16

Form.TopMost 설정


시도 해봤는데 ... 계속해서해야하나요? '미친 프로그램'이 즉시 인수됩니다 ...
jle

2
아니요-form.TopMost = true로 설정하면 작동합니다. "미친"프로그램에는 대화 상자가 TopMost로 설정되어 있어야합니다.이 경우 재정의 할 수 없습니다.
Reed Copsey

공정한 싸움이 아닙니다. 감사합니다.
jle

11

나는 순간적으로 5 분의 경과가 있었고 다음과 같이 전체 양식을 지정하는 것을 잊었습니다.

  myformName.ActiveForm.TopMost = true;

그러나 내가 정말로 원했던 것은 이것이었다!

  this.TopMost = true;

나를 위해 완벽하게 일했습니다. if (checkBox1.Checked == true) {this.TopMost = true; } else {this.TopMost = false; }
yosh

6

양식의 .TopMost속성을 true로 설정 합니다.

항상 이런 식으로 남겨두고 싶지는 않을 것입니다. 외부 프로세스가 시작될 때 설정하고 완료되면 다시 넣으십시오.


5

이 문제를 해결 한 방법은 취소 옵션이있는 시스템 트레이 아이콘을 만드는 것입니다.


5

다음 코드는 창을 항상 상단에 유지하고 프레임없이 만듭니다.

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace StayOnTop
{
    public partial class Form1 : Form
    {
        private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
        private const UInt32 SWP_NOSIZE = 0x0001;
        private const UInt32 SWP_NOMOVE = 0x0002;
        private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

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

        public Form1()
        {
            InitializeComponent();
            FormBorderStyle = FormBorderStyle.None;
            TopMost = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetWindowPos(this.Handle, HWND_TOPMOST, 100, 100, 300, 300, TOPMOST_FLAGS);
        }

        protected override void WndProc(ref Message m)
        {
            const int RESIZE_HANDLE_SIZE = 10;

            switch (m.Msg)
            {
                case 0x0084/*NCHITTEST*/ :
                    base.WndProc(ref m);

                    if ((int)m.Result == 0x01/*HTCLIENT*/)
                    {
                        Point screenPoint = new Point(m.LParam.ToInt32());
                        Point clientPoint = this.PointToClient(screenPoint);
                        if (clientPoint.Y <= RESIZE_HANDLE_SIZE)
                        {
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)13/*HTTOPLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)12/*HTTOP*/ ;
                            else
                                m.Result = (IntPtr)14/*HTTOPRIGHT*/ ;
                        }
                        else if (clientPoint.Y <= (Size.Height - RESIZE_HANDLE_SIZE))
                        {
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)10/*HTLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)2/*HTCAPTION*/ ;
                            else
                                m.Result = (IntPtr)11/*HTRIGHT*/ ;
                        }
                        else
                        {
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)16/*HTBOTTOMLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)15/*HTBOTTOM*/ ;
                            else
                                m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ;
                        }
                    }
                    return;
            }
            base.WndProc(ref m);
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.Style |= 0x20000; // <--- use 0x20000
                return cp;
            }
        }
    }
}

Alexan과 동의하십시오. 프로그램을 최고로 만드는 이유는 무엇입니까? 실제로 많은 경우에 작동하지 않는 "topmost = true"진술인 것 같습니다. 나머지 코드는 문제에 실제로 답하지 않습니다.
Fhaab

4

가시성을 억제하려는 다른 애플리케이션은 무엇입니까? 원하는 효과를 얻기위한 다른 방법을 조사 했습니까? 사용자가 설명하는 것과 같은 악의적 인 행동을 취하기 전에 그렇게하세요. 여러분이하려는 것은 특정 장난스러운 사이트가 브라우저 창에서하는 것과 비슷하게 들립니다.

최소한 Least Surprise 의 규칙을 고수하십시오 . 사용자는 대부분의 응용 프로그램의 z- 순서를 스스로 결정할 수 있기를 기대합니다. 당신은 그들에게 가장 중요한 것이 무엇인지 모르기 때문에, 당신이 무언가를 변경한다면, 당신은 자신의 것을 홍보하는 것보다 모든 뒤에 다른 애플리케이션을 밀어 붙이는 데 집중해야합니다.

물론 Windows에는 특히 정교한 창 관리자가 없기 때문에 이것은 더 까다 롭습니다. 두 가지 접근 방식이 제안합니다.

  1. 최상위 창을 열거 하고 그들이 속한 프로세스를 확인 하고 , 그렇다면 z 순서를 삭제합니다. . (이러한 WinAPI 함수에 대한 프레임 워크 메서드가 있는지 확실하지 않습니다.)
  2. 데스크톱에 액세스하는 것을 막기 위해 자식 프로세스 권한을 만지작 거리면서 ...하지만 다른 접근 방식이 실패 할 때까지 시도하지 않을 것입니다. 자식 프로세스가 사용자 상호 작용을 요구하면서 좀비 상태가 될 수 있기 때문입니다.

4

양식을 대화 상자로 만드는 것은 어떨까요?

myForm.ShowDialog();

1
예! 이것이 내가 원했던 것입니다. 설정 TopMost = true은 크롬을 포함한 모든 것 위에 내 양식을 강제로 적용했습니다. 현실에서는 설정 상자 일 뿐이며 기본 양식 위에 필요했습니다. 인터넷 사용자에게 찬사를 보냅니다.
MDMoore313

3

다음은 SetForegroundWindow에 해당하는 것입니다.

form.Activate();

나는 사람들이 다음과 같은 이상한 일을하는 것을 보았다.

this.TopMost = true;
this.Focus();
this.BringToFront();
this.TopMost = false;

http://blog.jorgearimany.com/2010/10/win32-setforegroundwindow-equivalent-in.html


내 창을 활성화하지 않으려면 맨 위에있는 창 (정보 용, 대화 형이 아닌) 만 원하면 어떻게해야합니까? 실제로 "topmost = True"를 발행하는 것이 제 경우에는 작동하지 않기 때문에 묻습니다 (다른 시스템에서는 작동하지 않고 시스템에서 작동 함).
Fhaab

이것이 우리에게 효과가 있음을 찾았습니다. this.Show(); this.Activate(); this.BringToFront(); 그러나이 대답은 우리에게 그 해결책 을 가져 왔습니다 . 감사!
jibbs

1

나는 이것이 오래되었다는 것을 알고 있지만이 반응을 보지 못했습니다.

창 (xaml)에서 다음을 추가합니다.

Deactivated="Window_Deactivated"

Window_Deactivated의 코드는 다음과 같습니다.

private void Window_Deactivated(object sender, EventArgs e)
    {
        Window window = (Window)sender;
        window.Activate();
    }

이렇게하면 창문이 맨 위에 유지됩니다.


1
질문이 winform에 관한 것이기 때문에이 응답을 보지 못했습니다.
Kinetic

1

를 기반으로 clamum의 대답, 그리고 케빈 Vuilleumier의 행동에 대한 책임을 다른 플래그에 대한 의견, 나는 사이에 전환이 전환했다 상단에있지 맨 앞면 버튼을 누를 때입니다.

private void button1_Click(object sender, EventArgs e)
    {
        if (on)
        {
            button1.Text = "yes on top";
            IntPtr HwndTopmost = new IntPtr(-1);
            SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
            on = false;
        }
        else
        {
            button1.Text = "not on top";
            IntPtr HwndTopmost = new IntPtr(-2);
            SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
            on = true;
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.