ウィンドウを常に.Netのトップに保つ方法は?


93

別のプログラムでマクロを実行するC#winformsアプリがあります。他のプログラムは継続的にポップアップウィンドウを表示し、一般的に物事をより良い言葉の欠如のために狂ったように見せます。プロセスの実行を停止するキャンセルボタンを実装したいのですが、ウィンドウが一番上に表示されないようです。C#でこれを行うにはどうすればよいですか?

編集:私はTopMost = trueを試しました。、しかし他のプログラムはそれ自身のウィンドウを上にポップアップし続けます。nミリ秒ごとにウィンドウを最上部に送信する方法はありますか?

編集:これを解決する方法は、システムトレイアイコンを追加することでした。このアイコンをダブルクリックすると、プロセスがキャンセルされます。システムトレイアイコンが隠れることはありません。ご回答くださった皆様、ありがとうございました。「スーパーオントップ」ウィンドウがない理由についての記事を読みました...論理的に機能しません。


62
はい、Form.TopMostをtrueに設定するタイマーを数ミリ秒ごとに設定します。次に、面白くするために、「クレイジー」プログラムがロードされたら、Mortal Kombatの「FIGHT!」のオーディオクリップを再生します。:-P
BFree

2
あなたのコメントは陽気だと思ったかもしれませんし、悪い習慣をばかにするかもしれないと思ったかもしれません。私の問題は、flowlayoutpanelを使用してフォーム上に浮かぶコンテキストメニューを作成することでした。flowlayoutpanelは、Activate()メソッドを呼び出した場合にのみスクロールできます。特定の状況では、Focus()では不十分です。スクロールできなくなります。それは排他的なtopmost = trueを持っている場合でも、コンテキストメニューからフォーカスを盗みます!いずれかの賢明な人は知っているように、それはあなたのWinフォームアプリケーションはMTAThreadモードで実行してみましょう、それが解決策を簡単に作る独自のスレッドのすべてのフォームを与えるために信心深いpractiveのです:
Traubenfuchs

1
見よ、悪魔:pastebin.com/sMJX0Yavちらつきなく完璧に動作し、sleep(1)で深刻なパフォーマンスが失われないようにするのに十分です。彼がコンテキストメニューに焦点を当てている間、誰がとにかく彼のタスクマネージャを見続けているのですか?コンテキストメニューが閉じると、空の例外ハンドラが実行されて終了します。isDisposedブレークを組み込むこともできます。
Traubenfuchs 2014

私はここに、この問題に対する私の解決策を掲載:stackoverflow.com/questions/2546566/...
KFN

@Traubenfuchs のでクロススレッド動作の例外で失敗します。これはうまくいくはずです。
mekb

回答:


171

Form.TopMost 他のプログラムが最上位のウィンドウを作成していない限り機能します。

別のプロセスの新しい最上位のウィンドウで覆われていないウィンドウを作成する方法はありません。レイモンド・チェンはその理由を説明しました。


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フラグはありますか?
マーク

この最上位の機能とデフォルトの動作を入れ替えたい場合は、良い質問です(たとえば、ウィンドウの動作に[常に一番上]チェックボックスがあります)。おそらく適切なフラグがあればそれは可能だと思います。デフォルトのウィンドウの動作を説明する正しいフラグ(SWP_DEFAULT = 0x0003など)がある場合、これらのフラグを使用して「SetWindowPos()」を再度呼び出すだけで済みます。よくわかりません。まだ調べていません。あなたがそうするなら幸運です、そして誰かがここにそれを追加してください!
clamum

これは通常の全画面ゲームモードでは機能しません
Sajitha Rathnayake、

2
@Markはい、フラグHWND_NOTOPMOST(= -2)があります。docs.microsoft.com/en-us/windows/win32/api/winuser/…を
Kevin Vuilleumier 19/07/17

23

「クレイジーになる」とは、各ウィンドウが他のウィンドウからフォーカスを奪い続けることを意味する場合、TopMostは問題を解決しません。

代わりに、試してください:

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

これにより、フォーカスを奪うことなく「子」フォームが表示されます。親がアクティブ化またはフォーカスされている場合でも、子フォームもその親の上に残ります。このコードは、所有者フォーム内から子フォームのインスタンスを作成した場合にのみ簡単に機能します。それ以外の場合は、APIを使用して所有者を設定する必要がある場合があります。


1
私がこれを正確に使用したことを本当にありがとう、それは完全に機能しました!
AvetisG

1
ありがとう..まさに私が探していたもの
Sameera Kumarasingha

CalledForm.Owner自分自身(CalledForm)に設定すると、System.ArgumentException次のようになります。 '循環制御参照が行われました。コントロールはそれ自体が所有または親にすることはできません。
mekb

2
これが、CalledFormではなくCallerFormを使用する理由です:)
Jesper

16

私が試した、これ...私は継続的にそれをしている必要がありますか?「クレイジーなプログラム」がすぐに引き継がれる...
jle

2
いいえ-form.TopMost = trueを設定すると、機能するはずです。「クレイジー」プログラムでは、ダイアログをTopMostにも設定する必要があります。この場合、オーバーライドすることはできません。
リードコプシー

公正な戦いではありません。ありがとうございました。
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;
            }
        }
    }
}

アレクサンと同意する-あなたのプログラムを一番上にしているものは何ですか?これは実際には「topmost = true」ステートメントだけのようで、多くの場合機能しません。残りのコードはすべて、実際には問題を解決しません。
Fhaab 2017

4

可視性を抑制しようとしている他のアプリケーションは何ですか?希望する効果を達成する他の方法を調査しましたか?あなたが説明しているような悪質な行動をユーザーに課す前にそうしてください:あなたが何をしようとしているのかは、特定のいたずらなサイトがブラウザウィンドウで行うのと同じように聞こえます...

少なくとも、最小サプライズのルールを遵守するようにしてください。ユーザーは、ほとんどのアプリケーションのzオーダーを自分で決定できることを期待しています。あなたは彼らにとって何が最も重要であるかわからないので、何かを変更する場合は、自分のアプリケーションを宣伝するのではなく、他のアプリケーションをすべての背後に置くことに焦点を当てるべきです。

Windowsには特に洗練されたウィンドウマネージャーがないため、これはもちろんトリッキーです。次の2つのアプローチが推奨されます。

  1. トップレベルウィンドウ列挙それらがどのプロセスに属している確認その場合はZオーダーを削除します。(これらのWinAPI関数のフレームワークメソッドがあるかどうかはわかりません。)
  2. 子プロセスのアクセス許可をいじって、デスクトップにアクセスできないようにします...しかし、子プロセスがゾンビ状態になり、ユーザーの操作が必要になる可能性があるため、他の方法が失敗するまで、これを試みません。

4

フォームをダイアログボックスにしないでください。

myForm.ShowDialog();

1
はい!これが私が欲しかったものです。Chrome TopMost = trueを含むすべてのものの上にフォームを強制的に設定すると、現実には単なる設定ボックスであり、メインフォームの上にそれを必要としました。あなたのインターネットの人への称賛。
MDMoore313 2016年

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 2017

これは私たちにとってうまくいくことがわかりました:this.Show(); this.Activate(); this.BringToFront(); しかし、この答えは私たちをその解決策に導きました。ありがとう!
jibbs 2017年

1

これは古いことはわかっていますが、この応答はありませんでした。

ウィンドウ(xaml)に次を追加します。

Deactivated="Window_Deactivated"

Window_Deactivatedのコードビハインド:

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

これにより、ウィンドウが前面に表示されます。


1
質問はwinformに関するものなので、この応答は表示されませんでした。
キネティック2018

1

基づいてclamumの答え、そしてケビン・ヴィルミエの行動に責任を他のフラグについてのコメント、私が切り替わり、このトグル作らトップにしていない上、トップボタンを押すとします。

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.