2017-09-05 80 views
1

我有選擇ListView項目時執行的代碼。由於此代碼可能需要很長時間才能執行,因此我想在運行時顯示ActivityIndicator如何正確使用異步/等待顯示Xamarin表單活動指示器

我已閱讀了大量有關ActivityIndicator的帖子,我相信我已將它正確設置。我很確定我的問題是由於UI在運行過程中完全凍結導致運行代碼阻塞了UI線程。

我已經通過每一個變化,我已經能夠找到使用異步/等待沒有運氣,所以我假設我仍然在做一些不正確的事情。

這裏是我的代碼:

private ListItem selectedList; 
public ListItem SelectedList 
{ 
    get 
    { 
     return selectedList; 
    } 
    set 
    { 
     if (selectedList != value) 
     { 
      var oldValue = selectedList; 
      selectedList = value; 
      buildThisList(); 
     } 
    } 
} 

private async void buildThisList() 
{ 
    StatusBarIsVisibile = true; 
    ThisList = Task.Run(async() => 
    { 
     return await buildBnBList(SelectedList, selectedLocation, 
         thisYearList.ListId) 
         .ConfigureAwait(false); 
    }).Result; // 1.8 seconds 
    StatusBarIsVisibile = false; 
    ThisList.MainVM = this; 
    ThisList.BuildView(); 
    PIShowListHeaderText = SelectedList.Title.Trim(); 
} 

private async Task<BnBList> buildBnBList(ListItem pSelectedList, State pselectedLocation, int pListId) 
{ 
    BnBList newList = new BnBList(pSelectedList, pselectedLocation, pListId); 
    List<BirdsnBflysMaster> bbfList = 
     App.BnBRepo.GetBirdsnBflys(selectedList.ListType); // 1.3 seconds 
    Lists parentList = App.BnBRepo.GetAList(SelectedList.ListId); // .5 seconds 
    BnBItem newBnBItem; 
    foreach (BirdsnBflysMaster bbf in bbfList) // .4 seconds 
    { 
     newBnBItem = new BnBItem(parentList, bbf, selectedLocation, newList, thisYearList.ListId); 
     newList.ListAll.Add(newBnBItem); 
     if (newBnBItem.ListTypeID == "Bird") 
     { 
      ... 
     } 
     else 
     { 
      ... 
     } 
    }    
    return newList; 
} 

所以:

  • buildThisList被調用時SelectedList屬性更改。
  • buildThisList來電buildBnBList這是耗時的過程。
  • buildBnBList沒有任何異步完成。
  • StatusBarIsVisibleActivityIndicatorIsVisibleIsRunning都結合。

我該如何編碼,以便執行buildBnBList不會阻塞UI線程?

回答

3

是的你是一個混合阻塞(.Result)與異步代碼,可能導致死鎖。應該避免使用async void,除非在偶數處理程序中。

那麼爲什麼不這樣做呢?

創建事件和事件處理程序。

public event EventHandler ListSelected = delegate { } 

現在應該允許您創建一個事件處理程序

private async void OnListSelected(object sender, EventArgs e) { 
    StatusBarIsVisibile = true; 
    ThisList = await buildBnBList(SelectedList, selectedLocation, thisYearList.ListId); 

    StatusBarIsVisibile = false; 
    ThisList.MainVM = this; 
    ThisList.BuildView(); 
    PIShowListHeaderText = SelectedList.Title.Trim(); 
} 

你顯然會訂閱事件(當然在生命週期的早期)

this.ListSelected += OnListSelected; 

並根據需要提高事件

private ListItem selectedList; 
public ListItem SelectedList { 
    get { 
     return selectedList; 
    } 
    set { 
     if (selectedList != value) { 
      var oldValue = selectedList; 
      selectedList = value; 
      OnListSelected(this, EventArgs.Empty); 
     } 
    } 
} 
+0

感謝您的意見。我想我明白你的建議。我在我的代碼中實現了它,但它沒有任何區別。如果我在運行之前設置了StatusBarIsVisibile = true,則ActivityIndi​​cator正在旋轉。當我點擊一個列表項時,微調框會停止,在用戶界面中沒有任何事情發生,直到完成OnListSelected。此時ActivityIndi​​cator再次開始旋轉,我選中的項目被突出顯示。 – DaveS