Как показать форму спереди в C # - PullRequest
21 голосов
/ 12 июня 2009

Люди,

Пожалуйста, кто-нибудь знает, как показать форму из невидимого в противном случае приложения, и имеет ли он фокус (т.е. появляется поверх других окон)? Я работаю в C # .NET 3.5.

Я подозреваю, что выбрал "совершенно неправильный подход" ... Я делаю , а не Application.Run (новый TheForm ()) вместо I (новый TheForm ()). ShowModal () ... Форма - это в основном модальное диалоговое окно с несколькими флажками; текстовое поле, а также кнопки ОК и Отмена. Пользователь устанавливает флажок и вводит описание (или что-то еще), затем нажимает кнопку ОК, форма исчезает, и процесс считывает введенные пользователем данные из формы, удаляет их и продолжает обработку.

Это работает, за исключением случаев, когда форма показывает, что она не получает фокус, вместо этого она появляется за приложением "хост", пока вы не нажмете на нее на панели задач (или что-то еще). Это очень раздражающее поведение, которое, как я прогнозирую, вызовет много «обращений в службу поддержки», и в существующей версии VB6 такой проблемы нет, поэтому я возвращаюсь к юзабилити ... и пользователи не примут это (и и не должны).

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

Так, пожалуйста, кто-нибудь знает, как "заставить" форму .NET 3.5 (честным путем или птицу) получить фокус? Я думаю, что "волшебные" вызовы API Windows (я знаю

Сумеречная зона: Это только кажется проблемой на работе, мы используем Visual Studio 2008 на Windows XP с пакетом обновления 3 (SP3) ... Я просто не смог воспроизвести проблему с SSCCE (см. Ниже) дома на Visual C # 2008 на Vista Ulimate ... Это прекрасно работает. А? WTF?

Кроме того, я клянусь, что вчера на работе показывал форму, когда я запускал EXE, но не когда F5 (или Ctrl-F5) прямо из IDE (с которой я только что мирился) .. Дома форма показывает хорошо в любом случае. Тотально запутанно!

Это может или не может иметь значение, но Visual Studio рухнул и сгорел сегодня утром, когда проект работал в режиме отладки и редактировал код «на лету» ... он застрял в том, что, как я предполагал, было бесконечным цикл сообщений об ошибках. Сообщение об ошибке было что-то вроде «не удается отладить этот проект, потому что это не текущий проект, или что-то ... Так что я просто убил его с помощью Process Explorer. Он снова запустился нормально, и даже предложил восстановить" потерянный файл, предложение, которое я принял.

using System;
using System.Windows.Forms;

namespace ShowFormOnTop {
    static class Program {
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Form1());
            Form1 frm = new Form1();
            frm.ShowDialog();
        }
    }
}

Справочная информация: Я портирую существующую реализацию VB6 на .NET ... Это "плагин" для "клиентского" ГИС-приложения с именем MapInfo . Существующий клиент "работал незаметно", и мои инструкции заключаются в том, чтобы "сохранить новую версию как можно ближе к старой версии", что работает достаточно хорошо (после нескольких лет исправлений); он просто написан на неподдерживаемом языке, поэтому нам нужно его портировать.

О себе: Я в значительной степени новичок в C # и .NET в целом, хотя у меня есть сертификат на чистку дна, я являюсь профессиональным программистом в течение 10 лет; Так что я вроде "знаю кое-что".

Любые идеи будут приветствоваться ... и спасибо всем, что нашли время, чтобы прочитать это далеко. Последовательность не является (очевидно) моей сильной стороной.

Приветствия. Кит.

Ответы [ 11 ]

47 голосов
/ 12 июня 2009

Просто

yourForm.TopMost = true;
4 голосов
/ 12 июня 2009

Существует перегрузка Form.ShowDialog (), которая принимает объект IWin32Window. Это IWin32Window обрабатывается как родительское окно для формы.

Если у вас есть родительское окно как System.Windows.Forms.Form, продолжайте и просто пропустите его. Если нет, получите HWND (возможно, с помощью P / Invoking для FindWindow ()) и создайте фиктивную реализацию IWin32Window, которая просто возвращает HWND ( Подробнее ).

3 голосов
/ 18 апреля 2012

Form.Activate() работал в моем случае.

3 голосов
/ 12 июня 2009
  1. Вы сказали, что он отлично работает при использовании Application.Run. Почему бы вам не использовать Application.Run, тогда?
  2. Вы пытались звонить BringToFront() с OnLoad или OnShown?
2 голосов
/ 03 марта 2014

Это окончательное решение, которое я написал после 20 различных попыток:

/* A workaround for showing a form on the foreground and with focus,
 * even if it is run by a process other than the main one
 */
public static void ShowInForeground(this Form form, bool showDialog = false)
{
    if (showDialog)
    {
        //it's an hack, thanks to http://stackoverflow.com/a/1463479/505893
        form.WindowState = FormWindowState.Minimized;
        form.Shown += delegate(Object sender, EventArgs e) {
            ((Form)sender).WindowState = FormWindowState.Normal;
        };
        form.ShowDialog();
    }
    else
    {
        //it's an hack, thanks to http://stackoverflow.com/a/11941579/505893
        form.WindowState = FormWindowState.Minimized;
        form.Show();
        form.WindowState = FormWindowState.Normal;

        //set focus on the first control
        form.SelectNextControl(form.ActiveControl, true, true, true, true);
    }
}
1 голос
/ 09 июля 2013

Activate() работал для меня тоже.

BringToFront() ничего не сделал в этом случае, я не знаю почему.

1 голос
/ 29 апреля 2010

Я взломал это из приложения, над которым работал. У нас есть большое приложение, которое загружает серию модулей, написанных разными командами. Мы написали один из этих модулей, и нам нужно было открыть диалог входа в систему во время этой инициализации. Было установлено значение .TopMost = true, но это не сработало.

Он использует WindowsFormsSynchronizationContext, чтобы открыть диалоговое окно, а затем получить результат этого диалогового окна обратно.

Я редко занимаюсь кодированием GUI и подозреваю, что это может быть излишним, но это может помочь кому-то, если он застрянет. У меня были проблемы с пониманием того, как состояние передается в SendOrPostCallback, так как все примеры, которые я мог найти, не использовали его.

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

public bool Dummy()
{

// create the login dialog
DummyDialogForm myDialog = new DummyDialogForm();

// How we show it depends on where we are. We might be in the main thread, or in a background thread
// (There may be better ways of doing this??)
if (SynchronizationContext.Current == null)
{
    // We are in the main thread. Just display the dialog
    DialogResult result = myDialog.ShowDialog();
    return result == DialogResult.OK;
}
else
{
    // Get the window handle of the main window of the calling process
    IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle;

    if (windowHandle == IntPtr.Zero)
    {
        // No window displayed yet
        DialogResult result = myDialog.ShowDialog();
        return result == DialogResult.OK;
    }
    else
    {
        // Parent window exists on separate thread
        // We want the dialog box to appear in front of the main window in the calling program
        // We would like to be able to do 'myDialog.ShowDialog(windowHandleWrapper)', but that means doing something on the UI thread
        object resultState = null;
        WindowsFormsSynchronizationContext.Current.Send(
            new SendOrPostCallback(delegate(object state) { resultState = myDialog.ShowDialog(); }), resultState);

        if (resultState is DialogResult)
        {
            DialogResult result = (DialogResult) resultState;
            return result == DialogResult.OK;
        }
        else
            return false;

    }
}

}

0 голосов
/ 26 октября 2018

Я получил код в проекте.

private static extern bool SetForegroundWindow(
IntPtr hWnd); 
public static void ShowToFront(Form form)
{
    FormWindowState oldState = form.WindowState;
    form.WindowState = FormWindowState.Minimized;
    form.Show();

    form.Activate();
    form.TopLevel = false;
    form.TopLevel = true;
    form.SelectNextControl(form.ActiveControl, true, true, true, true);
    SetForegroundWindow(form.Handle);
    form.Focus();
    form.WindowState = oldState;
}
0 голосов
/ 18 апреля 2018

Это отлично сработало:

formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();
0 голосов
/ 27 сентября 2013

Это то, что я использую, чтобы вывести открытую форму, которая является частью моего приложения, на передний план. Вы даже можете использовать его с кнопкой. Но форма должна быть открыта, иначе приложение сломается.

"YourOpenForm" должно быть именем вашей формы из окна свойств.

    private void button1_Click(object sender, EventArgs e)
    {
        Application.OpenForms["YourOpenForm"].BringToFront();
    }

Удачи!

...