Как сделать «всплывающее» (подсказка, выпадающее, всплывающее) окно в Winforms? - PullRequest
7 голосов
/ 29 декабря 2011

Как я могу сделать, как я назову, «всплывающее окно» в WinForms?


Поскольку я использовал свое собственное выдуманное слово «всплывающее окно» ,позвольте мне привести примеры этого так называемого «всплывающего» окна:

  • окно всплывающей подсказки (может выходить за пределы родительской формы, не отображаетсяв панели задач, не является модальным и не крадет фокус):

    enter image description here

  • a всплывающее меню окно (можно расширитьвне границ родительской формы, не отображается на панели задач, не является модальным и не крадет фокус):

    enter image description here

  • a раскрывающееся окно (может выходить за пределы родительской формы, не отображается на панели задач, не является модальным и не захватывает фокус):

    enter image description here

  • A главное меню окно (может выходить за пределы родительской формы, не отображается на панели задач, не является модальным и не воруетфокус):

    enter image description here

  • Обновление A всплывающее окно не создает себя «активное» окно при взаимодействии с использованием мыши или клавиатуры (окно «владелец» остается активным окном):

enter image description here

Атрибуты, которые я ищу в этом мифическом «всплывающем окне», таковы:

  • может расширять за пределы родительской формы (т.е. не является дочерним окном )
  • не отображается в панель задач (т. Е. Эвристика окна, окна которой должны появляться, не срабатывает и не имеет расширенного стиля окна WS_EX_APPWINDOW)
  • не является модальным (то есть не отключает своего "владельца" )
  • не крадет фокус
  • всегда поверх его«владелец»
  • не становится «активным» окном при взаимодействии с (владелец остается активным)

приложениям Windows уже удается создать такие окна,Как я могу сделать это в приложении WinForms?

Смежные вопросы

  • Как мне добиться всего вышеперечисленного в нативном коде?
  • Как создать всплывающее окноокно в Delphi?
  • у меня есть этот нативный код для отображения всплывающего окна - какие P / Invokes требуются для выполнения тех же действий в .NET?
  • у меня есть набор P/ Invoke в .NET - могу ли я повторно использовать обычную WinForm, переопределяя определенные методы, для достижения того же эффекта?
  • У меня есть WinForm, который я показываю как «всплывающее окно» при переопределении определенных методов - есть ливстроенный Control, который может выступать для меня как всплывающее окно?
  • Как смоделировать выпадающее окно в WinForms?

Попытка # 1

я попробовал метод Show(onwer) + ShowWithoutActivation:

PopupForm dd = new PopupForm ();
dd.Show(this);

с помощью PopupForm:

public class PopupForm: Form
{
    public PopupForm()
    {
        InitilizeComponent();
    }

    private void InitilizeComponent()
    {
        this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
        this.WindowState = FormWindowState.Normal;
        this.ShowInTaskbar = false;
    }

    protected override bool ShowWithoutActivation
    { get { return true; } }
}

Очень почти решил проблему, но затем я обнаруженное напомнило о другом свойстве «всплывающих» окон: они не получают фокус от своей формы «владельца» становятся активными, когдаen взаимодействует с мышью или клавиатурой.

Ответы [ 3 ]

3 голосов
/ 01 января 2012

Мне было любопытно, как работают выпадающие списки и меню, поэтому я провел еще несколько исследований.

Существует два основных подхода.

Создать всплывающее окно как перекрывающееся окно, которым владеет главное окно

Этот метод требуется, если во всплывающем окне есть встроенные элементы управления или если вы хотите, чтобы всплывающее окно велось как немодальное диалоговое окно.

Если пользователь собирается взаимодействовать с дочерними элементами управления во всплывающем окне, он должен получить активацию. (Таким образом, различные методы блокирования активации, такие как обработка WM_MOUSEACTIVATE, являются «красными сельдями».) И когда он получает активацию, Windows деактивирует главное окно. Исправление для этого состоит в том, чтобы отправить сообщение WM_NCACTIVATE родителю, чтобы обновить его внешний вид без изменения статуса активации. Этот подход используется в .Net ToolStrip, и мой другой ответ иллюстрирует его с помощью кода.

Создать всплывающее окно как дочернее окно рабочего стола

Этот метод используется выпадающими списками в выпадающих списках и (я полагаю) меню, но вы не можете встроить дочерние элементы управления, поэтому он не имеет широкого применения.

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

Однако это не так просто реализовать. Активация остается за основным приложением, поэтому она сохраняет фокус и получает нажатия клавиш. Кажется, это исключает встроенные элементы управления во всплывающем окне, поскольку они не могут получить фокус. Комбо-бокс обрабатывает это, перенаправляя сообщения нажатия клавиш в выпадающий список. (Обратите внимание, что меню, выпадающие списки и т.д. все полностью нарисованы владельцем в том смысле, что у них нет встроенных окон.)

3 голосов
/ 29 декабря 2011

Вы хотите собственное окно. В вашей основной форме:

private void showPopup_Click(object sender, EventArgs e)
{
    PopupForm popupForm = new PopupForm();
    // Make "this" the owner of form2
    popupForm.Show(this);
}

PopupForm должен выглядеть следующим образом:

public partial class PopupForm : Form
{
    private bool _activating = false;

    public PopupForm()
    {
        InitializeComponent();
    }

    // Ensure the popup isn't activated when it is first shown
    protected override bool ShowWithoutActivation
    {
        get
        {
            return true;
        }
    }

    private const int WM_NCACTIVATE = 0x86;

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

    protected override void WndProc(ref Message m)
    {
        // The popup needs to be activated for the user to interact with it,
        // but we want to keep the owner window's appearance the same.
        if ((m.Msg == WM_NCACTIVATE) && !_activating && (m.WParam != IntPtr.Zero))
        {
            // The popup is being activated, ensure parent keeps activated appearance
            _activating = true;
            SendMessage(this.Owner.Handle, WM_NCACTIVATE, (IntPtr) 1, IntPtr.Zero);
            _activating = false;
            // Call base.WndProc here if you want the appearance of the popup to change
        }
        else
        {
            base.WndProc(ref m);
        }
    }
}

И убедитесь, что PopupForm.ShowInTaskbar = false.

0 голосов
/ 11 марта 2016

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

hWnd = CreateWindowEx(..., WS_CHILDWINDOW | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS, ..., GetDesktopWindow(), ...);
SetWindowPos(hWnd, HWND_TOPMOST, ..., SWP_NOACTIVATE);

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

...