Можно ли использовать ShowDialog, не блокируя все формы?

Я надеюсь, что смогу объяснить это достаточно ясно. У меня есть основная форма (A), и она открывает 1 дочернюю форму (B) с помощью form.Show () и вторую дочернюю форму (C) с помощью form.Show (). Теперь я хочу, чтобы дочерняя форма B открывала форму (D) с помощью form.ShowDialog (). Когда я это делаю, он блокирует форму A и форму C. Есть ли способ открыть модальное диалоговое окно и заблокировать только ту форму, которая его открыла?

Для информации добавлен пример потоковой передачи

Marc Gravell 09.01.2009 18:56

Вопрос помечен как Winforms, но я попал сюда с той же проблемой с WPF. Для людей, ищущих такую ​​информацию c-диез-openfiledialog-немодально-возможно

NGI 28.02.2017 23:30
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
55
2
73 846
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Ответ принят как подходящий

Если вы запустите форму B в отдельном потоке от A и C, вызов ShowDialog заблокирует только этот поток. Понятно, что это, конечно, нетривиальное вложение работы.

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

Джон Т. - Необязательно, но вам лучше знать, что вы делаете, и надеяться, что между ними нет взаимодействия - звучит для меня как проблема.

Sam Meldrum 09.01.2009 18:45

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

Jon Tackabury 09.01.2009 18:46

Конечно, это беда, если ты не знаешь, что делаешь. Но если предположить, что эти двое не общаются (или связь столь же проста, как чтение некоторых данных из формы D после ее закрытия), реализовать это тривиально.

TheSmurf 09.01.2009 18:46

Весь пользовательский интерфейс не обязательно должен выполняться в одном потоке, вам просто нужно быть уверенным, что вы получаете доступ к свойствам пользовательского интерфейса формы в потоке пользовательского интерфейса этой формы. Итак, если A и B работают в разных потоках, если A обращается к B, ему нужно будет выполнить Invoke. В нашем приложении все формы запускаются в собственных потоках.

Rob Prouse 09.01.2009 18:47

Это отличная информация. Я знал, что вам нужно использовать invoke для доступа к элементам пользовательского интерфейса, но у меня сложилось ложное впечатление, что вам также нужно хранить все эти элементы пользовательского интерфейса в одном потоке. Лучше всего запускать его в отдельном потоке.

Jon Tackabury 09.01.2009 18:51

Следует отметить, что, хотя вам может быть комфортно с несколькими потоками пользовательского интерфейса, более поздние разработчики могут не подходить. Размещение этого в другом потоке пользовательского интерфейса требует дорогостоящего обслуживания, если вы не единственный разработчик.

Greg D 09.01.2009 20:40

@Greg D: Мы не говорим здесь о написании планировщика ОС; то, что для этого нужно знать, вероятно, является минимальной информацией, которую каждый программист настольных приложений должен знать о многопоточности.

TheSmurf 03.02.2009 19:37

примеры могли бы быть хорошими.

T.Todua 22.08.2019 00:54

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

[STAThread]
static void Main() {
    Application.EnableVisualStyles();
    Button loadB, loadC;
    Form formA = new Form {
        Text = "Form A",
        Controls = {
            (loadC = new Button { Text = "Load C", Dock = DockStyle.Top}),
            (loadB = new Button { Text = "Load B", Dock = DockStyle.Top})
        }
    };
    loadC.Click += delegate {
        Form formC = new Form { Text = "Form C" };
        formC.Show(formA);
    };
    loadB.Click += delegate {
        Thread thread = new Thread(() => {
            Button loadD;
            Form formB = new Form {
                Text = "Form B",
                Controls = {
                    (loadD = new Button { Text = "Load D",
                        Dock = DockStyle.Top})
                }
            };
            loadD.Click += delegate {
                Form formD = new Form { Text = "Form D"};
                formD.ShowDialog(formB);
            };
            formB.ShowDialog();  // No owner; ShowDialog to prevent exit
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    };
    Application.Run(formA);
}

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

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

Jon Tackabury 09.01.2009 18:56

Запустите FormB в новом потоке в FormA:

        (new System.Threading.Thread(()=> {
            (new FormB()).Show();
        })).Start();

Теперь любые формы, открытые в новом потоке с помощью ShowDialog (), будут блокировать только FormB, а НЕ FormA или FormC.

Использование нескольких потоков графического интерфейса - непростое дело, и я бы не советовал этого делать, если это ваша единственная мотивация для этого.

Гораздо более подходящий подход - использовать Show() вместо ShowDialog() и отключать форму владельца до тех пор, пока не вернется всплывающая форма. Есть всего четыре соображения:

  1. Когда используется ShowDialog(owner), всплывающая форма остается поверх своего владельца. То же самое и при использовании Show(owner). В качестве альтернативы вы можете явно установить свойство Owner с тем же эффектом.

  2. Если вы установите для свойства Enabled формы владельца значение false, форма будет отображать отключенное состояние (дочерние элементы управления выделены серым цветом), тогда как при использовании ShowDialog форма владельца по-прежнему отключается, но не отображает отключенное состояние.

    Когда вы вызываете ShowDialog, форма владельца отключается в коде Win32 - устанавливается бит стиля WS_DISABLED. Это приводит к тому, что он теряет способность фокусироваться и "звенеть" при нажатии, но не заставляет его рисовать себя серым.

    Когда вы устанавливаете свойство Enabled формы на false, устанавливается дополнительный флаг (в структуре, а не в базовой подсистеме Win32), который определенные элементы управления проверяют, когда они рисуют себя. Этот флаг указывает элементам управления рисовать себя в отключенном состоянии.

    Итак, чтобы имитировать то, что произойдет с ShowDialog, мы должны установить бит собственного стиля WS_DISABLED напрямую, вместо того, чтобы устанавливать свойство Enabled формы на false. Это достигается с помощью небольшого взаимодействия:

    const int GWL_STYLE   = -16;
    const int WS_DISABLED = 0x08000000;
    
    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    
    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    
    void SetNativeEnabled(bool enabled){
        SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) &
            ~WS_DISABLED | (enabled ? 0 : WS_DISABLED));
    }
    
  3. Вызов ShowDialog() не возвращается, пока диалоговое окно не будет закрыто. Это удобно, потому что вы можете приостановить логику в форме владельца, пока диалог не сделает свое дело. Вызов Show() не обязательно ведет себя подобным образом. Следовательно, если вы собираетесь использовать Show() вместо ShowDialog(), вам нужно разбить вашу логику на две части. Код, который должен запускаться после закрытия диалогового окна (включая повторное включение формы владельца), должен запускаться обработчиком событий Closed.

  4. Когда форма отображается как диалоговое окно, установка ее свойства DialogResult автоматически закрывает ее. Это свойство устанавливается всякий раз, когда нажимается кнопка со свойством DialogResult, отличным от None. Форма, показанная с помощью Show, не будет автоматически закрываться таким образом, поэтому мы должны явно закрыть ее при нажатии одной из кнопок закрытия. Обратите внимание, однако, что свойство DialogResult по-прежнему устанавливается соответствующей кнопкой.

Реализуя эти четыре вещи, ваш код становится примерно таким:

class FormB : Form{
    void Foo(){
        SetNativeEnabled(false); // defined above
        FormD f = new FormD();
        f.Closed += (s, e)=>{
            switch(f.DialogResult){
            case DialogResult.OK:
                // Do OK logic
                break;
            case DialogResult.Cancel:
                // Do Cancel logic
                break;
            }
            SetNativeEnabled(true);
        };
        f.Show(this);
        // function Foo returns now, as soon as FormD is shown
    }
}

class FormD : Form{
    public FormD(){
        Button btnOK       = new Button();
        btnOK.DialogResult = DialogResult.OK;
        btnOK.Text         = "OK";
        btnOK.Click       += (s, e)=>Close();
        btnOK.Parent       = this;

        Button btnCancel       = new Button();
        btnCancel.DialogResult = DialogResult.Cancel;
        btnCancel.Text         = "Cancel";
        btnCancel.Click       += (s, e)=>Close();
        btnCancel.Parent       = this;

        AcceptButton = btnOK;
        CancelButton = btnCancel;
    }
}

+1 гораздо более полный ответ, чем мой - но по сути тот же подход! Избавлюсь от моего, потому что твое намного более полно.

Sam Meldrum 09.01.2009 20:07

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

nightcoder 11.09.2011 02:32

@nightcoder: Я знаю, что прошел год, но я только что заметил твой комментарий. Образец, который я привел выше, действительно вызывает мигание формы переднего плана (FormD) и воспроизведение звука дина. Возможно, в вашем коде вы не установили свойство owner в FormD (в моем примере это делается путем передачи this в f.Show(), но вы также можете установить f.Owner = this). Это необходимо для мигания собственного окна. Но даже без этого это должно звучать, и мне это нравится.

P Daddy 22.09.2012 11:47

@ p-daddy: Спасибо за этот фрагмент кода. Это помогло реализовать подобное решение для моих нужд: stackoverflow.com/a/16088711/654244

KyleK 18.04.2013 20:47

Я реализовал это решение, и оно отлично сработало. Спасибо. Я добавлю, однако, что моя форма все равно вышла бы на первое место среди всех других форм приложения, если бы родительский элемент в настоящее время не был активен. Это не то, что я хотел. Поэтому я активировал это, только если ActiveForm был родительской формой. В противном случае я устанавливаю свойство в самой родительской форме, чтобы открыть форму в событии Activated родительской формы.

jaredbaszler 15.07.2016 07:51

Я знаю, что он очень старый, но вместо использования GetWindowLong / SetWindowLong вы можете просто использовать EnableWindow.

Gabriel Luci 30.01.2017 21:36

Обратите внимание также на то, чтобы отключить все остальные окна приложения, кроме диалогового окна переднего плана. И активируйте окно владельца после его повторного включения, иначе оно потеряет фокус (по крайней мере, в WPF это так).

ygoe 13.12.2017 16:47

Я столкнулся с аналогичной проблемой в написанном мной приложении. Моим основным пользовательским интерфейсом была форма, работающая в основном потоке. У меня был диалог справки, который я хотел запустить как немодальный диалог. Это было легко реализовать, даже до такой степени, что у меня всегда был запущен только один экземпляр диалогового окна справки. К сожалению, любые модальные диалоги, которые я использовал, также приводили к потере фокуса диалогового окна справки - когда это было, когда некоторые из этих модальных диалогов были запущены, наличие диалогового окна справки было бы наиболее полезным.

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

Я объявил поток внутри своего основного пользовательского интерфейса.

Thread helpThread;

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

private void Help(object sender, EventArgs e)
{
    //if help dialog is still open then thread is still running
    //if not, we need to recreate the thread and start it again
    if (helpThread.ThreadState != ThreadState.Running)
    {
        helpThread = new Thread(new ThreadStart(startHelpThread));
        helpThread.SetApartmentState(ApartmentState.STA);
        helpThread.Start();
    }
}

void startHelpThread()
{
    using (HelpDialog newHelp = new HelpDialog(resources))
    {
        newHelp.ShowDialog();
    }
}

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

public MainWindow()
{
    ...
    helpThread = new Thread(new ThreadStart(startHelpThread));
    helpThread.SetApartmentState(ApartmentState.STA);
    ...
}

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

helpDialog.Abort();

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

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

Я просто хотел добавить сюда свое решение, так как оно мне подходит и может быть инкапсулировано в простой метод расширения. Единственное, что мне нужно сделать, это разобраться с миганием, поскольку @nightcoder прокомментировал ответ @ PDaddy.

public static void ShowWithParentFormLock(this Form childForm, Form parentForm)
{
  childForm.ShowWithParentFormLock(parentForm, null);
}

public static void ShowWithParentFormLock(this Form childForm, Form parentForm, Action actionAfterClose)
{
  if (childForm == null)
    throw new ArgumentNullException("childForm");
  if (parentForm == null)
    throw new ArgumentNullException("parentForm");
  EventHandler activatedDelegate = (object sender, EventArgs e) =>
  {
    childForm.Focus();
    //To Do: Add ability to flash form to notify user that focus changed
  };
  childForm.FormClosed += (sender, closedEventArgs) =>
    {
      try
      {
        parentForm.Focus();
        if (actionAfterClose != null)
          actionAfterClose();
      }
      finally
      {
        try
        {
          parentForm.Activated -= activatedDelegate;
          if (!childForm.IsDisposed || !childForm.Disposing)
            childForm.Dispose();
        }
        catch { }
      }
    };
  parentForm.Activated += activatedDelegate;
  childForm.Show(parentForm);
}
+1 Спасибо, что поделились !! Ты действительно спас мне день !!
Anne 26.02.2013 19:10

@Anne, я думаю, ты забыл нажать +1 :)

Justin Pihony 26.02.2013 20:47

Оказывается, единственное, что вам нужно, чтобы дочерняя форма мигала, когда кто-то пытается выбрать родительскую форму, - это добавить parentForm.Enabled = false; перед childForm.Show(parentForm);. Только не забудьте добавить parentForm.Enabled = true; до или после parentForm.Focus();. @JustinPihony, спасибо за ваше решение, простое и эффективное.

Korli 22.12.2016 16:34

Возможно, дочернее окно (подробности см. В ChildWindow) было бы более элегантным решением, и оно позволило бы избежать всех проблем с отдельными потоками для графического интерфейса.

Я хотел бы обобщить возможные решения и добавить одну новую альтернативу (3a и 3b). Но сначала я хочу уточнить, о чем мы говорим:

У нас есть приложение с несколькими формами. Требуется показать модальный диалог, который блокирует только определенное подмножество наших форм, но не другие. Модальные диалоги могут отображаться только в одном подмножестве (сценарий A) или нескольких подмножествах (сценарий B).

А теперь краткое изложение возможных решений:

  1. Не используйте модальные формы, показанные через ShowDialog(), вообще

    Подумайте о дизайне своего приложения. Вам действительно нужно использовать метод ShowDialog()? Если вам не нужна модальная форма, это самый простой и чистый способ.

    Конечно, это решение не всегда подходит. Есть некоторые особенности, которые дает нам ShowDialog(). Наиболее примечательным является то, что он отключает владельца (но не выделяется серым цветом), и пользователь не может взаимодействовать с ним. Очень утомительный ответ предоставил P Папа.

  2. Эмулировать поведение ShowDialog()

    Можно имитировать поведение этого метода. Снова рекомендую прочитать P Ответ папы.

    а) Использование комбинация Свойство Enabled на Form и отображение формы как немодальной через Show(). В результате отключенная форма будет недоступна. Но это полностью управляемое решение без необходимости взаимодействия.

    б) Не нравится, что родительская форма неактивна? Ссылка на несколько собственных методов и отключить бит WS_DISABLED в родительской форме (еще раз - см. Ответ от P Папа).

    Эти два решения требуют, чтобы у вас был полный контроль над всеми диалоговыми окнами, которые вам нужно обрабатывать. Вы должны использовать специальную конструкцию для отображения «частично блокирующего диалога» и не должны забывать об этом. Вам необходимо настроить логику, потому что Show() не блокирует, а ShowDialog() блокирует. Работа с системными диалоговыми окнами (средства выбора файлов, средства выбора цвета и т. д.) Может быть проблемой. С другой стороны, вам не нужен дополнительный код в формах, который не должен блокироваться диалогом.

  3. Преодолеть ограничения ShowDialog()

    Обратите внимание, что есть события Application.EnterThreadModal и Application.LeaveThreadModal. Это событие возникает всякий раз, когда отображается модальный диалог. Помните, что события на самом деле охватывают весь поток, а не приложение.

    а) Слушайте событие Application.EnterThreadModal в формах, которые не должны блокироваться диалогом, и включить бит WS_DISABLED в этих формах. Вам нужно только настроить формы, которые не должны блокироваться модальными диалогами. Вам также может потребоваться проверить родительскую цепочку показываемой модальной формы и переключить WS_DISABLED на основе этого условия (в вашем примере, если вам также нужно открывать диалоги с помощью форм A и C, но не блокировать формы B и D).

    б) Скрыть и повторно показать формы, которые нельзя блокировать. Обратите внимание, что когда вы показываете новую форму после отображения модального диалога, она не блокируется. Воспользуйтесь этим, и когда появится модальный диалог, скройте и снова покажите желаемые формы, чтобы они не блокировались. Однако такой подход может вызвать мерцание. Теоретически это можно исправить, включив / отключив перерисовку форм в Win API, но я этого не гарантирую.

    c) Установите свойство Owner в диалоговую форму в формах, которые не должны блокироваться при отображении диалога. Я этого не тестировал.

    г) Используйте несколько потоков графического интерфейса. Ответ от TheSmurf.

Очень хорошо. Думаю, это лучший ответ.

Xan-Kun Clark-Davis 21.09.2016 18:58

Пример использования:

(new NoneBlockingDialog((new frmDialog()))).ShowDialogNoneBlock(this);

Исходный код:

class NoneBlockingDialog
{
    Form dialog;
    Form Owner;

    public NoneBlockingDialog(Form f)
    {
        this.dialog = f;
        this.dialog.FormClosing += new FormClosingEventHandler(f_FormClosing);
    }

    void f_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (! e.Cancel)
            PUtils.SetNativeEnabled(this.Owner.Handle, true);
    }

    public void ShowDialogNoneBlock(Form owner)
    {
        this.Owner = owner;
        PUtils.SetNativeEnabled(owner.Handle, false);
        this.dialog.Show(owner);
    }
}

partial class PUtils
{
            const int GWL_STYLE = -16;
    const int WS_DISABLED = 0x08000000;


    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);


    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);


    static public void SetNativeEnabled(IntPtr hWnd, bool enabled)
    {
        SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_DISABLED | (enabled ? 0 : WS_DISABLED));
    }
}

Вот помощник, который я использую в WPF, чтобы предотвратить блокировку диалоговыми окнами не диалоговых окон на основе некоторых ответов на этот вопрос:

public static class WindowHelper
{
    public static bool? ShowDialogNonBlocking(this Window window)
    {
        var frame = new DispatcherFrame();

        void closeHandler(object sender, EventArgs args)
        {
            frame.Continue = false;
        }

        try
        {
            window.Owner.SetNativeEnabled(false);
            window.Closed += closeHandler;
            window.Show();

            Dispatcher.PushFrame(frame);
        }
        finally
        {
            window.Closed -= closeHandler;
            window.Owner.SetNativeEnabled(true);
        }
        return window.DialogResult;
    }

    const int GWL_STYLE = -16;
    const int WS_DISABLED = 0x08000000;

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    static void SetNativeEnabled(this Window window, bool enabled)
    {
        var handle = new WindowInteropHelper(window).Handle;
        SetWindowLong(handle, GWL_STYLE, GetWindowLong(handle, GWL_STYLE) &
            ~WS_DISABLED | (enabled ? 0 : WS_DISABLED));
    }
}

Применение:

if (true == window.ShowDialogNonBlocking())
{
    // Dialog result has correct value
}

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

Я был уверен, что делал это раньше, но попробовав, ну что ты знаешь, даже Microsoft Word не может этого сделать. Он ведет себя точно так же, как описано в OP: как только вы открываете модальное диалоговое окно (например, «Найти и заменить» с помощью Ctrl + H), ВСЕ документы Word блокируются и с ними невозможно взаимодействовать. Что еще хуже, только щелчок по исходному родительскому документу вызывает мигание модального диалогового окна. Остальные просто не отвечают и не намекают, почему они заблокированы или что нужно закрыть.

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

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


Я понимаю, что это технически не «решение». Те, кто действительно считает, что их приложение должно поддерживать полностью независимые родительские формы, могут попробовать обходной путь от @PDaddy, который кажется очень тщательным.

Однако, надеюсь, это дает немного спокойствия тем, кто (как и я) просто пытался сознательно относиться к своему пользовательскому интерфейсу и думал, что делает что-то не так. Ты не сумасшедший. Видимо, именно так и работает Windows.

Другие вопросы по теме