Синхронное ожидание без блокировки потока пользовательского интерфейса

#.net #wpf #vb.net #multithreading #wait

#.net #wpf #vb.net #многопоточность #подождите

Вопрос:

Существует ли функция синхронного ожидания, которая не будет связывать пользовательский интерфейс с потоком в .NET WPF? Что-то вроде:

 Sub OnClick(sender As Object, e As MouseEventArgs) Handles button1.Click
     Wait(2000) 
     'Ui still processes other events here
     MessageBox.Show("Is has been 2 seconds since you clicked the button!")
End Sub
  

Комментарии:

1. в обычном Win32 вы можете использовать MsgWaitForMultipleObjects для достижения этой цели.

Ответ №1:

Вы можете использовать DispatcherTimer для такого рода вещей.

Редактировать: Это тоже может сработать…

 private void Wait(double seconds)
{
    var frame = new DispatcherFrame();
    new Thread((ThreadStart)(() =>
        {
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            frame.Continue = false;
        })).Start();
    Dispatcher.PushFrame(frame);
}
  

( Dispatcher.PushFrame документация.)


Начиная с .NET 4.5 вы можете использовать async обработчики событий и Task.Delay для получения такого же поведения. Просто позволить обновлению пользовательского интерфейса во время такого возврата обработчика Dispatcher.Yield .

Комментарии:

1. В WPF вы демонстративно хотите использовать DispatcherTimer, поскольку его тики будут выполняться в потоке пользовательского интерфейса, позволяя вам изменять элементы управления пользовательского интерфейса. Если вы используете стандартный таймер, тики выполняются в своем собственном потоке, и вы получите несколько неприятных исключений, если попытаетесь коснуться элементов управления пользовательского интерфейса. 1

2. Можно ли в любом случае использовать таймер для выполнения встроенного ожидания. Кажется громоздким и трудным для чтения, когда вы разбиваете метод каждый раз, когда вам нужно подождать.

3. @PeterM: Поскольку я не слишком хорошо разбираюсь в вопросах потоковой обработки, возможно, вы захотите взглянуть на ссылку на модель потоковой обработки и Dispatcher.PushFrame метод, который может помочь вам упростить это.

4. @PeterM: На самом деле, я думаю, что я только что получил решение, используя этот метод, смотрите Мой обновленный ответ. (Хотя я не говорю на VB …)

5. В качестве примера неблокирующего ожидания события в C #

Ответ №2:

Вот решение с Task.Delay . Я использую это в модульных тестах для ViewModel ов, которые используют DispatcherTimer .

 var frame = new DispatcherFrame();

var t = Task.Run(
    async () => {
        await Task.Delay(TimeSpan.FromSeconds(1.5));
        frame.Continue = false;
    });

Dispatcher.PushFrame(frame);

t.Wait();