Очень странная ошибка при использовании Show Dialog на C # Winform

Я создал 2 формы в VS Studio 2008 Express Edition и объявил их с помощью public static в основном файле program.cs

Я просто хочу переключаться между двумя формами с помощью ShowDialog и Close, но при попытке закрыть вторую форму и снова открыть первую форму с помощью showdialog он говорит, что я не могу использовать showDialog, когда форма уже видна, тогда как это неверно, так как я закрыл его перед тем, как показать вторую форму.

Он попросил меня установить для свойства form visible значение false перед использованием showdialog, поэтому я сделал это

    internal static void CloseSecondForm(FirstForm FirstForm)
    {
        FirstForm .Close();
        SecondForm.Visible = false;
        SecondForm.ShowDialog();
    }

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

    internal static void CloseSecondForm(FirstForm FirstForm)
    {
        FirstForm .Close();
        SecondForm.Visible = false;
        SecondForm.Close();
        SecondForm.ShowDialog();
    }

Но он все равно делает вид, что форма уже открыта с помощью ShowDialog!

Это Баг в моей проге или в Winform?

Обновление: это весь код, который я опубликовал в 5-м ответе (я хочу использовать showdialog и не показывать, потому что у меня может быть 3-я форма в фоновом режиме, к которой я не хочу, чтобы пользователь имел доступ):

  [STAThread]
  static void Main()
  {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      Form1 = new Form1();
      Form2 = new Form2();
      Form1.ShowDialog();
      Application.Run();

  }

  // called from Form1 BUTTON
  internal static void ShowForm2(Form1 Form1)
  {
      Form1.Hide();
      Form2.ShowDialog();
  }

  // called from Form2 BUTTON
  internal static void ShowForm1(Form2 Form2)
  {
      Form2.Hide();
      Form1.ShowDialog();
  }

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

  using System;
  using System.Windows.Forms;

  namespace twoforms
  {
      static class Program
      {
          /// <summary>
          /// The main entry point for the application.
          /// </summary>
          /// 
          public static Form1 Form1;
          public static Form2 Form2;

          [STAThread]
          static void Main()
          {
              Application.EnableVisualStyles();
              Application.SetCompatibleTextRenderingDefault(false);
              Form1 = new Form1();
              Form2 = new Form2();
              Form1.ShowDialog();
              Application.Run();

          }

          // called from Form1 BUTTON
          internal static void ShowForm2(Form1 Form1)
          {
              Form1.Hide();
              Form2.ShowDialog();
          }

          // called from Form2 BUTTON
          internal static void ShowForm1(Form2 Form2)
          {
              Form2.Hide();
              Form1.ShowDialog();
          }
      }
  }

person programmernovice    schedule 02.08.2009    source источник
comment
Можете ли вы опубликовать небольшой фрагмент приложения, которое вызывает эти методы?   -  person JP Alioto    schedule 02.08.2009
comment
Да, я это сделал, см. 5-й ответ ниже.   -  person programmernovice    schedule 02.08.2009
comment
Вы можете (должны) отредактировать свой собственный вопрос вместо того, чтобы публиковать ответ с дополнительной информацией.   -  person Henk Holterman    schedule 02.08.2009
comment
Кроме того, не стоит полагаться на расположение ответов - они могут сильно колебаться из-за голосования.   -  person Lucas Jones    schedule 02.08.2009


Ответы (5)


Это из MSDN:

Когда форма отображается как модальное диалоговое окно, нажатие кнопки «Закрыть» (кнопка с X в правом верхнем углу формы) приводит к скрытию формы и присвоению свойству DialogResult значения DialogResult.Cancel. В отличие от немодальных форм, метод Close не вызывается платформой .NET Framework, когда пользователь нажимает кнопку закрытия формы в диалоговом окне или устанавливает значение свойства DialogResult. Вместо этого форма скрыта и может быть отображена снова без создания нового экземпляра диалогового окна. Поскольку форма, отображаемая как диалоговое окно, не закрывается, вы должны вызвать метод Dispose формы, когда форма больше не нужна вашему приложению.

Итак, как только вы показываете форму с помощью ShowDialog и теперь хотите ее закрыть, просто позвольте ей вернуть DialogResult.Cancel. Это скроет (она все еще будет в памяти) вашу первую форму. Теперь вы можете вызвать ShowDialog во второй форме. Опять же, если вы хотите переключиться на первую форму, позвольте второй форме вернуть DialogResult.Cancel, а теперь просто вызовите ShowDialog в первой форме.

person P.K    schedule 02.08.2009

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

Лучшее решение - не делать эти формы статичными, а вместо этого просто создавать новые экземпляры каждой формы по мере необходимости. Второе лучшее решение - использовать Show вместо ShowDialog; если у вас все равно отображается только одна из этих форм, ShowDialog не имеет смысла.

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

person MusiGenesis    schedule 02.08.2009
comment
Почему с тех пор, как я впервые закрываю форму? Я хочу использовать ShowDialog, потому что это блокирующее окно, у меня может быть третья форма в фоновом режиме, к которой я не хочу, чтобы пользователь имел доступ. - person programmernovice; 02.08.2009
comment
Я могу сделать это на VB или VBA, почему я не могу сделать это на C #? - person programmernovice; 02.08.2009
comment
Неважно, что вы закрываете первую форму. Поскольку вы показываете вторую форму из первой, первая остается активной, что бы вы ни делали. - person MusiGenesis; 02.08.2009
comment
Я не думаю, что вы можете сделать это в VB или VBA. Если можете, значит, ShowDialog там не работает. - person MusiGenesis; 02.08.2009
comment
Кроме того, если у вас есть третья форма в фоновом режиме, просто убедитесь, что код, который показывает две другие формы (A и B), вызывается из третьей формы (а не из A или B). - person MusiGenesis; 02.08.2009
comment
Ключом к пониманию проблемы является то, что ShowDialog является блокирующим вызовом, то есть обработчик кнопки никогда не может завершить работу, а окно никогда не закрывается. Если ShowDialog не является блокирующим вызовом в VBA, тогда моя память, должно быть, покидает меня. - person AaronLS; 02.08.2009
comment
@aaronls: Я использовал Visual Basic более 10 лет. ShowDialog всегда был блокирующим вызовом. - person MusiGenesis; 02.08.2009
comment
Я могу возразить, что лучший подход - создать два UserControl и показать их в одной и той же форме. Это было бы неплохо для решения проблемы, с которой спрашивающий столкнется с re: где его новая форма появляется на экране. - person Greg D; 02.08.2009
comment
@Greg: Я думаю, что лучший подход - просто использовать ваши формы обычным способом - когда вам нужно показать форму, создайте новый экземпляр, а затем покажите его с помощью ShowDialog. - person MusiGenesis; 02.08.2009

Попробуйте использовать Hide () вместо Close (). У меня была аналогичная проблема в прошлом, и Hide () работал у меня.

person Freddy    schedule 02.08.2009
comment
Справа: Close выполняет дополнительные обязанности по уборке, а Hide в основном приравнивается к Visible=false. - person peSHIr; 02.08.2009
comment
Спасибо, я безуспешно пытался скрыть, хотя весь код см. В 5-м ответе. - person programmernovice; 02.08.2009

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

Это немного надуманный пример, но каждая форма здесь просто имеет одну кнопку с DialogResult, установленным на OK.

[STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        bool exit = false;
        while (true)
        {
            if (exit) break;
            using (Form1 frm = new Form1())
            {
                switch(frm.ShowDialog())
                {
                    case DialogResult.OK:
                        break;
                    default:
                        exit = true;
                        break;
                }   
            }
            if(exit) break;
            using (Form2 frm = new Form2())
            {
                switch(frm.ShowDialog())
                {
                    case DialogResult.OK:
                        break;
                    default:
                        exit = true;
                        break;
                } 
            }

        }

    }

для выхода просто нажмите красную кнопку закрытия (x).

person Dog Ears    schedule 02.08.2009
comment
Конечно, у вас может быть только один экземпляр каждой формы new'd до цикла while, и вы можете отказаться от использования операторов и многократно показывать одни и те же экземпляры двух форм. - person Dog Ears; 02.08.2009
comment
Это будет та же концепция, что и диспетчер окон / состояний. Форма уведомит о создании класса, сообщив, какая кнопка была нажата, установив переменную. После закрытия формы оконный менеджер обрабатывает запрос. - person AaronLS; 02.08.2009

Обратите внимание на разницу между Close и Hide. И разница между Show и ShowDialog.

Мне не совсем понятно, чего вы хотите достичь; вы только (частично) описываете в коде то, что вы сделали, и симптом возникшей проблемы. Не могли бы вы описать, что вы пытаетесь сделать?

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

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

person peSHIr    schedule 02.08.2009
comment
Выложили всю программу ниже. - person programmernovice; 02.08.2009