Как сделать окно всегда оставаться на вершине в .Net?

У меня есть приложение winforms С#, которое запускает макрос в другой программе. Другая программа будет постоянно всплывать окна и, как правило, делать вещи, из-за отсутствия лучшего слова, сумасшедшие. Я хочу реализовать кнопку отмены, которая остановит процесс, но я не могу заставить окно оставаться на вершине. Как это сделать на С#?

Изменить: я попробовал TopMost = true;, но другая программа продолжает всплывать вверх по своим окнам. Есть ли способ отправить мое окно вверху каждые n миллисекунд?

Изменить: способ, которым я решил это, - добавить значок в системном трее, который отменит процесс, дважды щелкнув по нему. Значок в системном трее не закрывается. Спасибо всем, кто ответил. Я прочитал статью о том, почему нет окна "супер-сверху"... это логически не работает.

Ответ 1

Form.TopMost будет работать, если другая программа не создаст самые верхние окна.

Невозможно создать окно, которое не покрыто новыми верхними окнами другого процесса. Раймонд Чен объяснил почему.

Ответ 2

Я искал, чтобы сделать мое приложение 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);

Надеюсь, что это поможет. Ссылка

Ответ 3

Если "сойти с ума" вы имеете в виду, что каждое окно продолжает красть фокус от другого, TopMost не решит проблему.

Вместо этого попробуйте:

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

Это покажет "дочернюю" форму без кражи фокуса. Детальная форма также останется на вершине родителя, даже если родитель активирован или сфокусирован. Этот код работает легко, только если вы создали экземпляр дочерней формы из формы владельца. В противном случае вам может потребоваться установить владельца с помощью API.

Ответ 5

Задайте для свойства .TopMost значение true.

Вы, вероятно, не хотите оставлять это так все время: установите его, когда ваш внешний процесс запустится и вернет его, когда он закончит.

Ответ 6

У меня был краткий 5-минутный промежуток, и я забыл полностью указать форму следующим образом:

  myformName.ActiveForm.TopMost = true;

Но я действительно хотел ЭТОГО!

  this.TopMost = true;

Ответ 7

То, как я решил это, было создание значка в системном трее, у которого была опция отмены.

Ответ 8

Следующий код заставляет окно всегда оставаться на вершине, а также сделать его бескаркасным.

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;
            }
        }
    }
}

Ответ 9

Какое другое приложение вы пытаетесь подавить видимость? Изучали ли вы другие способы достижения желаемого эффекта? Пожалуйста, сделайте это, прежде чем подвергать своих пользователей воздействию таких изгоев, которые вы описываете: то, что вы пытаетесь сделать, похоже на то, что некоторые непослушные сайты делают с окнами браузера...

По крайней мере, попытайтесь придерживаться правила Наименьший сюрприз. Пользователи ожидают, что смогут определить z-порядок большинства приложений. Вы не знаете, что для них наиболее важно, поэтому, если вы что-то измените, вам следует сосредоточиться на том, чтобы подталкивать другое приложение за всем, а не продвигать свои собственные.

Это, конечно, сложнее, поскольку Windows не имеет особо сложного оконного менеджера. Предлагаются два подхода:

Ответ 10

Почему бы не сделать вашу форму диалоговым окном:

myForm.ShowDialog();

Ответ 12

Я знаю, что это старый, но я не видел этот ответ.

В окне (xaml) добавьте:

Deactivated="Window_Deactivated"

В коде для Window_Deactivation:

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

Это будет держать ваше окно на вершине.

Ответ 13

Основываясь на ответе 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;
        }
    }