Сон работает, не останавливая пользовательский интерфейс

1

Я написал эту простую программу, чтобы подождать 2 секунды, а затем обновить текстовое поле:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < 10; i++)
            {
                doSomething(i);
            }
        }
        public void doSomething(int i)
        {
            System.Threading.Thread.Sleep(2000);
            textBox1.Text += "this is the " + i + "th line\n";
        }
    }
}

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

есть ли альтернатива вместо System.Threading.Thread.Sleep?

  • 2
    Имейте другой поток сна, и когда это будет сделано, сделайте свое действие.
  • 2
    Используйте таймер. Никогда не спите () в главном потоке.
Теги:
wpf
user-interface
sleep
thread-sleep

3 ответа

4
Лучший ответ

Вы можете использовать async/await, не блокируя поток пользовательского интерфейса.

for (int i = 0; i < 10; i++)
{
    await doSomething(i);
}

public async Task doSomething(int i)
{
    await Task.Delay(2000);
    this.Text += "this is the " + i + "th line\n";
}
  • 0
    смешно, написал тоже самое
  • 0
    моя программа не знает асинхронность и задачу как ключевое слово, я должен использовать какую-то библиотеку или ссылку? (я использую .net 4)
Показать ещё 2 комментария
3

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

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

private void button1_Click(object sender, RoutedEventArgs args)
{
    int i = 0;
    DispatcherTimer timer = new DispatcherTimer();
    timer.Interval = TimeSpan.FromSeconds(2);
    timer.Tick += (s, e) =>
    {
        if (i == 10)
        {
            timer.Stop();
        }
        else
        {
            textBox1.Text += "this is the " + i + "th line\n";
            ++i;
        }
    };
    timer.Start();
}

Примечание. Я предлагаю DispatcherTimer здесь вместо класса Timer, потому что Timer выполняет обработчик обработчика Elapsed в фоновом потоке, поэтому для обновления интерфейса вы должны делегировать код в диспетчере пользовательского интерфейса. Но DispatcherTimer выполняет обработчик события Tick в потоке пользовательского интерфейса, поэтому нет необходимости снова выводить данные на диспетчер интерфейса.

1

Простой способ:

private void button1_Click(object sender, RoutedEventArgs e)
{
    DoSomethingAsync();
}

private async void DoSomethingAsync()
{
    for (int i = 0; i < 10; i++)
    {
        await doSomething(i);
    }
}

async Task doSomething(int i)
{
    await Task.Delay(1000);
    textBox1.Text += "this is the " + i + "th line\n";
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню