Я не могу закрыть эту форму - PullRequest
4 голосов
/ 02 июня 2019

почему я не могу закрыть это, из-за этого я получил сообщение об ошибке (операция с несколькими потоками недопустима: доступ к элементу управления Form4 осуществляется из потока, отличного от потока, в котором он был создан)

код моей формы;

 System.Timers.Timer t = new System.Timers.Timer();

private void Form4_Load(object sender, EventArgs e)
    { myFunction2();}
private void myFunction2()
    {
        t.Interval = int.Parse(textBox1.Text);
        t.Elapsed += T_Elapsed;
        t.Start();
        t.AutoReset = false;

    }
 private void T_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {

        myFunction();

        t.Stop();
        t.Enabled = false;
        this.Close();
    }
private void myFunction()
    {


        var form6 = new Form6();
        //form6.Closed += (s, args) => this.Close();
        form6.ShowDialog();}

Редактировать Я получаю помощь от друга, чтобы изменить это в моем коде, но все равно открываются from4 и form6 много времени.

 private System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();

private void myFunction2()
    {
         t.Interval = int.Parse(textBox1.Text);
        t.Tick += T_Elapsed;
        t.Start(); 
    }
 private void T_Elapsed(object sender, EventArgs e)
    {
        myFunction();
        this.Invoke((new Action(() => 
                       this.Close();
        }))); 
    }
 private void myFunction()
    {
        Form6 form6 = new Form6();
        form6.ShowDialog();}

Ответы [ 2 ]

2 голосов
/ 02 июня 2019

Winforms имеет модель «собственный поток».

Что это значит?

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

Почему?

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

Но почему это происходит, вы?

Поскольку System.Timers.Timer выполняет свой обратный вызов в своем собственном потоке, который не является потоком, создавшим GUI (основной поток приложения).Таким образом, вы не можете получить доступ из его обратного вызова к любому компоненту графического интерфейса.

Какое решение?

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

Просто используйте System.Windows.Forms.Timer вместо System.Timers.Timer.Этот таймер специфичен для WinForms и обрабатывает всю черную работу с диспетчером за вас.(Примечание: WPF имеет System.Windows.Threading.DispatcherTimer для той же цели).

Но есть один подводный камень: у этого таймера нет свойства AutoReset.Итак, вы должны удалить событие вручную после одного запуска, например:

private void T_Elapsed(object sender, EventArgs e)
{
    myFunction();

    t.Stop();
    this.Close();
}

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

Кроме того, обратите внимание, что вам не нужны оба Stop() и Enabled = false вместе, они идентичны (лично я предпочитаю Stop(), я думаю, что это более читабельно).

В вашем примере (с * 1042)*) вам вообще не нужно было Stop() - AutoReset = false запускать обратный вызов только один раз.

Редактировать:

Хотя в вашем случае это не требуется, я добавляюобъяснение о том, «как использовать диспетчер».

Каждая форма WinForms имеет Dispatcher и некоторые методы, связанные с ним.Наиболее важными являются Invoke() и BeginInvoke() (две перегруженные версии, я говорю о первой, которая занимает System.Delegate).

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

Разница в том, что Invoke() возвращается только после вызова метода, тогда как BeginInvoke() асинхронный;он возвращается немедленно.

Итак, вы можете переписать свой код следующим образом:

private System.Timers.Timer t = new System.Timers.Timer();

public Form1()
{
    InitializeComponent();

    t.Elapsed += T_Elapsed;
    t.Interval = int.Parse(textBox1.Text);
    t.AutoReset = false;
    t.Start();
}

private void T_Elapsed(object sender, EventArgs e)
{
    this.Invoke((Action)(() => // You can use `BeginInvoke()` as well
    {
        this.Close();
    }));
    // Or
    // this.Invoke(new Action(() => // You can use `BeginInvoke()` as well
    // {
    //     this.Close();
    // }));
}

Примечание: Никогда не помещайте долгосрочные задачи в Invoke() или BeginInvoke()!поскольку они выполняются в собственном потоке, а не в вызываемом потоке, они замораживают графический интерфейс - гораздо проще вообще не использовать потоки ... Поместите вычисления в поток и вызывайте эти методы только для обновленияGUI!

Edit 2:

После того, как я увидел, что вы сделали с моим ответом, я был шокирован ... Кажется, вы даже не читали его!Вы выбрали оба решения: таймер winforms (хороший) и диспетчер (в нашем случае, bas)!упростить вам Tick событие так:

private void T_Elapsed(object sender, EventArgs e)
{
    myFunction();
    Close();
}

Кроме того, в вашем myFunction() вы показываете свою вторую форму в модальной форме .Это говорит о том, что метод не вернется после закрытия второй формы.См. В чем разница между функциями Show (), ShowDialog () и Application.Run ()? для получения более подробной информации.Я думаю, что вы хотите показать свою вторую форму немодальной.

0 голосов
/ 03 июня 2019
private System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
private void T_Elapsed(object sender, EventArgs e)
    {
        if (true)
        {
            myFunction();
            t.Enabled = false;
            t.Stop();
        }
    }
 private void myFunction2()
    {
        t.Interval = int.Parse(textBox1.Text);
        t.Tick += T_Elapsed;
        t.Start();

    }
    private void myFunction()
    {
        t.Enabled = false;
        t.Stop();
        this.Hide();
        Form6 form6 = new Form6();
        form6.ShowDialog();}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...