В приложении c # winforms, почему этот цикл сна не работает? - PullRequest
0 голосов
/ 14 февраля 2019

Это не дубликат Thread.sleep () в то время как цикл не работает должным образом? Потому что один из принятых ответов заключается в том, что он перепутал миллисекунды и секунды.

Примечание: кто-то предположил, что Поддержка потока пользовательского интерфейса при запуске длинной задачи в формах Windows решит мой вопрос.Пример в этом вопросе очень сложен тем, что в нем есть много вещей, которые не относятся к делу, и ответы на них отвечают и включают всю эту сложность.Гораздо сложнее понять этот вопрос и ответить.Мой вопрос намного проще и, следовательно, ответ гораздо проще.Принятый ответ здесь не имеет token.ThrowIfCancellationRequested(); Очень сложно адаптировать сложный ответ по этой ссылке к моему простому вопросу.Я, конечно, не принял бы принятый ответ на этот вопрос как ответ на мой.Ганс фактически дал однострочный ответ.Я не думаю, что однострочный ответ относится к этому вопросу.Так что мой вопрос отличается от этого.


У меня есть форма с кнопкой и меткой

У меня есть этот код при нажатии кнопки

Aнажатие кнопки вызывает функцию, которая делает это

            int a, b;           
            int i=0;
            while(i<5)
            {
                i += 1;
                Thread.Sleep(1000);
                label1.Text += "a";               
            }
            MessageBox.Show("done");

Я бы "ожидал" / хотел, чтобы это записывало каждое из 5 'a, с паузой на секунду между каждым.

Но это не так, это их буферизирует.он ждет 5 секунд, затем записывает все «а» и печатает «готово».

Почему он буферизируется?

Я не хочу использовать таймер, потому что хочу, чтобы онбыть последовательным.Я не хочу, чтобы «готово» печаталось до тех пор, пока не будет выполнено заданное время.

Как получить код, который мне нужен, чтобы работать так, как я хочу?

На этот вопрос есть принятый ответ C # - Как приостановить приложение до завершения таймера? Я не совсем понимаю, я бы протестировал это, но я даже не вижу, как это проверить, потому что я не могу понять, куда я положил код из принятого ответа, как я бы его адаптировалhttps://i.imgur.com/gjRDEiX.png Возможно, принятый ответ имеет подкласс таймера или что-то в этом роде, и это не кажется необходимым для моей проблемы / вопроса.

Ответы [ 3 ]

0 голосов
/ 14 февраля 2019

Асинхронный подход является, по моему мнению, самым чистым.

Вот еще один подход, демонстрирующий, как обновить пользовательский интерфейс с помощью Invoke (), если вы когда-нибудь выберете более классический стиль Task / Thread:

    private void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;

        Task.Run(() => {
            int i = 0;
            while (i < 5)
            {
                i += 1;
                System.Threading.Thread.Sleep(1000);
                label1.Invoke((MethodInvoker) delegate {
                    label1.Text += "a";
                });

            }
            button1.Invoke((MethodInvoker) delegate {
                MessageBox.Show("done");
                button1.Enabled = true;
            });             
        });
    }
0 голосов
/ 14 февраля 2019

Просто предложение - используйте Microsoft Reactive Framework (Rx) - NuGet System.Reactive.Windows.Forms и вставьте using System.Reative.Linq; вверху кода.Тогда вы можете написать:

Observable
    .Interval(TimeSpan.FromSeconds(1.0))
    .Take(5)
    .ObserveOn(this)
    .Subscribe(_ => label1.Text += "a");
0 голосов
/ 14 февраля 2019

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

Старый способ

void SomeHandler(object sender, EventArgs e)
{
    int a, b;           
    int i=0;
    while(i<5)
    {
        i += 1;
        Thread.Sleep(1000);
        Application.DoEvents(); //Process events in the event queue
        label1.Text += "a";               
    }
    MessageBox.Show("done");
}

Новый способ

Чтобы это работало, выдолжен сделать ваш обработчик асинхронным.

async void SomeHandler(object sender, EventArgs e)
{
    int a, b;           
    int i=0;
    while(i<5)
    {
        i += 1;
        await Task.Delay(1000);  //The await keyword yields control to the caller
        label1.Text += "a";               
    }
    MessageBox.Show("done");
}

Последний метод считается лучшим.DoEvents почти повсеместно не одобряется разработчиками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...