2016-11-30 81 views
0

我在.NET 4.0應用程序中使用Modern UI for WPF模板,其中一個頁面在導航回到另一個頁面之前需要執行異步命令。同時,在命令運行時,UI線程必須解鎖。如果我這樣做:在導航前執行異步命令

public void OnNavigatingFrom(FirstFloor.ModernUI.Windows.Navigation.NavigatingCancelEventArgs e) 
    { 
     TaskEx.Run(() => 
      { 
       //Replace Sleep call by the async command execution 
       System.Threading.Thread.Sleep(5000); 
      }).Wait();} 

OnNavigatingFrom在導航回前等待,但在此期間UI被阻止。

關於如何在不同的上下文中執行異步代碼並使OnNavigatingFrom「同步」運行的任何想法?

編輯:有一個similar thread解決方法,沒有確鑿的答案。

+1

你確實意識到等待是一個阻止呼叫? –

+0

我這樣做,我知道這是一個問題。那麼考慮到調用方法(OnNavigatingFrom)在操作完成之前無法返回,我怎麼才能使它不被阻塞呢? –

+0

如果*(且僅當)* OnNavigatingFrom方法是一個事件處理程序,則可以將其設置爲「public async void」(感謝Stephen Cleary閱讀大量文獻)。這將允許你使用'await'。例如。 '等待DoSomethingAsync();'。調用方法將不會返回,直到等待完成的任務完成 –

回答

1

一個頁面需要執行異步逗號nd在導航回到另一頁之前

這就是問題所在。用戶界面不是異步的,句點。在UI正在進行轉換時,您不能將異步操作粘貼到組合中。想象一下這種方式:作爲一個用戶,如果你決定回去導航,並且存在網絡呃逆或者某些事情,並且程序在導航返回時凍結了幾秒鐘,那麼這是一種糟糕的用戶體驗,對吧? UI在更新期間根本無法等待異步工作。

你可以做的是做之前的工作用戶是允許導航回來。例如,您可以在操作完成時捕獲用戶的導航向導並顯示某種「請稍候」用戶界面的意圖,然後在操作完成後執行導航。

+0

你的建議是我在做什麼。問題在於,我的頁面執行的這個「導航回」方法(OnNavigatingFrom)不會等待異步操作,在操作正在進行時將顯示「請稍候」用戶界面。我最終做的是取消導航,做我的異步的東西,然後從我的ViewModel操作完成後導航回來。 –

+0

@IgorKondrasovas:是的,那就是你必須要做的。 'OnNavigatingFrom' *不能等待 - 它不應該等待 - 嘗試讓它等待是沒有意義的。 –

0

只是awaitTask而不是使用.Wait()

Using async-await on .net 4對如何在.NET 4.0

+0

等待該任務不起作用,因爲調用方法在導航返回之前不會等待完成。 –

+1

使用await意味着事件處理程序將不會返回,直到等待完成的任務完成,但UI將自由繼續。使用Wait()(或任何其他阻塞機制)將阻止UI。你不能兩面都有。也許你可以在await完成後設置一個標誌,UI線程中的其他代碼可以檢測到這個標誌嗎? – sellotape

+0

否則你不能在事件處理程序的等待結束後做你想做的事嗎? – sellotape

2

這裏等待是你需要做什麼:

public void OnNavigatingFrom(NavigatingCancelEventArgs e) 
{ 
    // Fire and forget. 
    Task.Run(() => MyCommandAsync()); 
} 

上面是發射後不管的做法,取而代之的則最好使用asyncawait

public async void OnNavigatingFrom(NavigatingCancelEventArgs e) 
{ 
    await MyCommandAsync(); 
} 
+1

這不起作用,因爲OnNavigatingFrom是一個事件處理程序,只是在方法頭上添加異步不會造成任何不同。該頁面將立即返回。 –

+1

@IgorKondrasovas這是使用正確事件的問題。使用'await'是等待異步操作的正確方法。你只是使用錯誤的事件/模式。代替*導航*你應該使用一個命令,在完成時導航到新頁面 –

+0

第一種形式將立即將「MyCommandAsync」的執行過程發佈到線程池中,並在第二種形式將在UI線程上運行時返回,直到它到達第一個不完整的候選人。 –

0

使用在導航從做你的東西。 e.Cancel阻止回頭。操作完成後使用Frame.GoBack()。

protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e) 
{ 
    if (Current.HasModifications()) 
    { 
     e.Cancel = true; 
     await Current.Save().ContinueWith((t) => 
     { 
      //Go Back after the Operation has finished 
      Frame.GoBack(); 
     }, TaskScheduler.FromCurrentSynchronizationContext()); 
    } 
    else 
    { 
     base.OnNavigatingFrom(e); 
    } 
}