Утилизировать форму после закрытия - PullRequest
12 голосов
/ 31 августа 2010

У меня новая проблема с открытием и закрытием формы в C #.

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

вот мой код:

Program.cs:

static class Program
{
    public static Timer timer;

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

        timer = new Timer { Interval = 1000};
        timer.Start();

        Application.Run(new Form1());
    }
}

Form1.cs:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Form2 form = new Form2();
        form.ShowDialog();
       /// I've tried Dispose() method . but didn't work
    }
}

Form2.cs:

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
    }

    private void Form2_Load(object sender, EventArgs e)
    {
        Program.timer.Tick += timer_Tick;    
        Close();
        // I've tried Dispose() method instead of Close() but didn't work
    }

    private int count = 0; 
    void timer_Tick(object sender, EventArgs e)
    {
        count++;
        if (count == 5) MessageBox.Show("");
    }
}

Отредактировано: Мой вопросis: почему окно сообщения отображается через 5 секунд после закрытия формы2!

Ответы [ 5 ]

8 голосов
/ 31 августа 2010

Редактировать: Этот вопрос, похоже, касается Dispose.

Во-первых, Dispose не имеет ничего общего с сборкой мусора. Происходит следующее:

  1. У вас есть глобальный экземпляр Timer
  2. Вы создаете форму2
  3. Form2 подписывается на таймер
  4. Форма 2 закрыта и / или утилизирована
  5. Событие Timer срабатывает, увеличивает счетчик и показывает MessageBox
  6. Событие Timer продолжается до тех пор, пока приложение не закроется.

Главное, что нужно понять, это то, что Close / Dispose изменяют только статус формы, они не могут (не могут) удалить экземпляр. Таким образом, (закрытая) форма есть, поле счетчика все еще там, и Событие запускается.


ОК, часть 1:

Блок using () {} был бы лучше, но это должно работать:

    private void button1_Click(object sender, EventArgs e)
    {
        Form2 form = new Form2();
        form.ShowDialog();
       /// I've tried Dispose() method . but didn't work
        form.Dispose(); // should work
    }

Если нет, опишите «не работает».


    private void Form2_Load(object sender, EventArgs e)
    {
        Program.timer.Tick += timer_Tick;    
        Close();
       /// I've tried Dispose() method instead of Close() . but didn't work
    }

Это странно, но я предполагаю, что это искусственный код для вопроса.

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

  1. Не делайте этого (дайте Form2 свой таймер)
  2. Используйте событие FormClosed для отмены подписки: Program.timer.Tick -= timer_Tick;
4 голосов
/ 31 августа 2010

Самый простой и надежный способ избавиться от Form после использования - поместить использование внутри блока использования

using (Form2 form = new Form2()) {
  form.ShowDialog();
}

Блок using в C # - это конструкция, которая существенно расширяет вышеперечисленное в следующем коде.

Form2 form;
try {
  form = new Form2(); 
  ...
} finally {
  if ( form != null ) {
    form.Dispose();
  }
}
3 голосов
/ 02 ноября 2013

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

Теперь конкретно о вашем коде. Давайте рассмотрим, что делает строка Program.timer.Tick += timer_Tick;. Это дает указатель на вашу функцию в объекте формы на объекте таймера . Так что теперь, независимо от того, что вы делаете с объектом Form , объект таймера будет продолжать вызывать эту функцию. Объект таймера не заботится о вашей Форме и даже не знает о существовании объекта Формы . Это касается только функции, которую вы передали указателю на . Что касается объекта таймера, эта функция является отдельной функцией.

Что делает Form.Close ()? Form.Close () располагает ресурсами, используемыми формой, то есть помечает элементы управления формой для сборки мусора , если форма не отображается с помощью ShowDialog. В этом случае Dispose () должен вызываться вручную. MSDN

Нет необходимости говорить (или, может быть, не так уж и бесполезно), что если закрытие / удаление формы удалит функцию из памяти, у объекта таймера будет недопустимый указатель, и ваша программа вылетит через 5 секунд.

1 голос
/ 22 октября 2012

Возможно, я неправильно читаю вопрос, но я думаю, что джентльмены должны знать, что для закрытия формы (скажем, form2), открытой как Form2.ShowDialog (), вам нужно установить Form2.DialogResult в Form2. Достаточно установить этот элемент, чтобы закрыть форму и вернуть результат.

0 голосов
/ 31 августа 2010

form.ShowDialog () показывает форму как модальное диалоговое окно.Это означает, что вызов не вернется, пока форма не будет закрыта.
Обратите внимание, что нажатие кнопки закрытия X в модальном диалоговом окне не закрывает форму, а просто скрывает ее.Я предполагаю, что это то, что вас смущает.Если вы хотите, чтобы код в form1 продолжал выполняться, а не блокироваться, вы должны вызвать Show () вместо ShowDialog ().Немодальное закроется при нажатии X.

Если вы хотите заблокировать модальное диалоговое окно, вы должны окружить форму блоком использования, как описано в других ответах.
При создании модального диалогаВы обычно добавляете кнопку «ОК» или аналогичную и устанавливаете для этой кнопки свойство AcceptButton формы, чтобы позволить пользователю закрыть форму, нажав клавишу ввода.Точно так же вы можете добавить кнопку «Отмена» и установить свойство CancelButton для захвата клавиши Esc.
Добавьте обработчик щелчка для двух кнопок, соответственно установите свойство DialogResult формы и вызовите Close ().

...