2013-04-05 2 views
-1
private void WaitForDriveToBecomeReady() 
{ 
    AutoResetEvent syncEvent = new AutoResetEvent(false); //set wait signal to use later 

    //dispatcher to be able to change stuff in xaml from within thread 
    Action action1 = new Action(delegate() { grdMain.Children.Add(notification); }); 
    Action action2 = new Action(delegate() { grdMain.Children.Remove(notification); }); 
    Thread restoreThread1 = new Thread(()=>{ 
     grdMain.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, action1); //show a notification 

     Thread.Sleep(1500); //sleep a bit... 

     grdMain.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, action2); //hide a notification 

     syncEvent.Set(); //signal to continue at *.WaitOne() 
    }); 
    restoreThread1.Start(); 

    syncEvent.WaitOne(); //let main thread wait until *.Set(); is called 
} 

Приведенный выше код работает идеально, если вы закомментировать две grdMain.Dispatcher.Invoke (...) ;. Он также работает perfekt, если вы закомментируете * .Set(); и * .WaitOne(); Но ПОЧЕМУ? Мне нужны оба ^^. Я не понимаю ...C# AutoResetEvent WaitOne останавливали диспетчерский

ответ

0

У меня, наконец, было время, чтобы продолжить читать о async и ждать. Спасибо @Jacob за то, что он указал, в чем проблема.

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

//the method 
public async Task WaitForDriveAsync(string path, string waitingToastText) 
{ 
    int width = 300; 
    int height = 125; 
    TextBlock toastTextBlock = new TextBlock() { Text = waitingToastText, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, FontSize = 23, Width = (width - 15), TextWrapping = TextWrapping.WrapWithOverflow }; 
    Grid notification = new Grid(); 
    notification.Width = width; 
    notification.Height = height; 
    notification.Background = Brushes.Red; 
    notification.Margin = new System.Windows.Thickness(0, 27, 0.4, 0); 
    notification.VerticalAlignment = VerticalAlignment.Top; 
    notification.HorizontalAlignment = HorizontalAlignment.Right; 
    notification.Children.Add(toastTextBlock); 

    grdMain.Children.Add(notification); 

    while (!Directory.Exists(path)) 
    { 
     await Task.Delay(1000); 
    } 

    grdMain.Children.Remove(notification); 
} 

//to call it 
private async void btnBackupNow_Click(object sender, RoutedEventArgs e) 
{ 
    await WaitForDriveAsync(@"B:\", "Please connect your drive."); 
} 
3

Предполагается, что WaitForDriveToBecomeReady вызывается в потоке Диспетчера, вы явно вводите тупик.

Рассмотрим ход выполнения

  • Вы создали событие сброса
  • нить начинает выполнение
  • Диспетчерский поток вызывает syncEvent.WaitOne(), что поток теперь заблокирован до тех пор, что событие не получает набор
  • Второй поток выполняет Dispatcher.Invoke; это помещает сообщение в очередь диспетчера и ждет, пока оно не обработает его (в основном потоке).

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

В общем, ожидание в потоке пользовательского интерфейса плохое; легко получить такие блокировки, но даже если это сработает, вы по-прежнему блокируете пользовательский интерфейс для обновления, создавая невосприимчивую программу. Основываясь на вышеприведенном фрагменте, трудно сказать, как лучше всего реорганизовать ваш код, чтобы вам не пришлось блокировать поток пользовательского интерфейса, но похоже, что эта концепция (подготовка диска и выполнение чего-то, когда он готов) был бы кандидатом для asynchronous method.

+0

Я думаю, вы поняли, что правильно. Проблема возникает только с этой диспетчерской линией, поэтому я думаю, потому что, используя основной поток, это ожидание в основном потоке становится несовместимым, не так ли? Извините, но это заняло у меня часы и сошло с ума ^^. – CodingYourLife

+0

Способ думать о том, что Dispatcher.Invoke очень похож на ваш код события + поток (как в концепции, так и в реализации). Он останавливает работу над другим потоком, а затем ждет, чтобы этот поток установил событие, когда работа выполнена. Поэтому у вас есть каждая нить, которая ничего не делает, ожидая, пока другой закончит свою работу. – Jacob

+0

Спасибо вам большое. Теперь я успел пройти несколько статей и, наконец, сделал это! Мне жаль, что вместо моего ответа я принял свой собственный ответ, но мне хотелось поделиться исходным кодом моей проблемы. – CodingYourLife

Смежные вопросы