2016-10-24 34 views
0

我正在使用xamarin格式。我想在日曆控件中綁定Web服務。請參閱下面的日曆控件鏈接(XamForms.Controls.Calendar)。如何從不是異步方法調用異步方法?

https://github.com/rebeccaXam/XamForms.Controls.Calendar

第一功能是創建7 * 6 = 42個標籤和按鈕然後「callWebService」方法來調用服務函數,它是異步方法來獲得從服務響應。

protected void FillCalendarWindows() 
     { 
      try 
      { 
       for (int r = 0; r < 6; r++) 
       { 
        for (int c = 0; c < 7; c++) 
        { 
         if (r == 0) 
         { 
          labels.Add(new Label 
          { 
           HorizontalOptions = LayoutOptions.Center, 
           VerticalOptions = LayoutOptions.Center, 
           TextColor = Color.Black, 
           FontSize = 18, 
           FontAttributes = FontAttributes.Bold 
          }); 
          DayLabels.Children.Add(labels.Last(), c, r); 
         } 
         buttons.Add(new CalendarButton 
         { 
          BorderRadius = 0, 
          BorderWidth = BorderWidth, 
          BorderColor = BorderColor, 
          FontSize = DatesFontSize, 
          BackgroundColor = DatesBackgroundColor, 
          HorizontalOptions = LayoutOptions.FillAndExpand, 
          VerticalOptions = LayoutOptions.FillAndExpand 
         }); 
         buttons.Last().Clicked += DateClickedEvent; 
         MainCalendar.Children.Add(buttons.Last(), c, r); 
        } 
       } 
       flag = 1; 
       //Device.BeginInvokeOnMainThread(() => CallWebService(StartDate.Month, StartDate.Year)); 
       CallWebService(StartDate.Month, StartDate.Year); 
       //CallServiceInNewTask(StartDate.Month, StartDate.Year); 
       //Device.BeginInvokeOnMainThread(() => ChangeCalendar(CalandarChanges.All)); 

      } 
      catch (Exception e) 
      { 

      } 
     } 

二功能是「callWebService」功能,我收集列表集合對象響應然後調用它是用來綁定標籤和按鈕上的文字,並填寫相應的顏色「ChangeClaendar」功能。

public async void CallWebService(int Month, int Year) 
     { 
      try 
      { 
       var response = await GetResponseFromWebService.GetResponse<ServiceClasses.RootObject_AttendanceTable>(ServiceURL.GetAttendanceTableList + "Month=" + Month + "&Year=" + Year + "&EmpCd=" + _empCode); 
       if (response.Flag == true) 
       { 
        if (ListObjAttendanceTblList == null) 
        { 
         ListObjAttendanceTblList = new List<LstAttendanceDtl>(); 
        } 
        for (int i = 0; i < response.lstAttendanceDtl.Count; i++) 
        { 
         var objAttendanceTableList = new LstAttendanceDtl(); 

         objAttendanceTableList.AttendanceDt = response.lstAttendanceDtl[i].AttendanceDt; 
         objAttendanceTableList.EarlyDeparture = response.lstAttendanceDtl[i].EarlyDeparture; 
         objAttendanceTableList.InTime = response.lstAttendanceDtl[i].EarlyDeparture; 
         objAttendanceTableList.LateArrival = response.lstAttendanceDtl[i].EarlyDeparture; 
         objAttendanceTableList.OutTime = response.lstAttendanceDtl[i].OutTime; 
         objAttendanceTableList.OverTime = response.lstAttendanceDtl[i].OverTime; 
         objAttendanceTableList.Reason = response.lstAttendanceDtl[i].Reason; 
         objAttendanceTableList.Remark = response.lstAttendanceDtl[i].Remark; 
         objAttendanceTableList.Shift = response.lstAttendanceDtl[i].Shift; 
         objAttendanceTableList.WorkingHrs = response.lstAttendanceDtl[i].WorkingHrs; 

         ListObjAttendanceTblList.Add(objAttendanceTableList); 
        } 
       } 
       else 
       { 
       } 
       if (flag == 1) 
       { 
        ChangeCalendar(CalandarChanges.All); 
       } 
       else 
       { 
        ChangeCalendar(CalandarChanges.StartDate); 
       } 
      } 
      catch (WebException e) 
      { 

      } 
     } 

第三個功能是 「ChangeCalendar」

protected void ChangeCalendar(CalandarChanges changes) 
     { 
      try 
      { 
       if (changes.HasFlag(CalandarChanges.StartDate)) 
       { 
        Device.BeginInvokeOnMainThread(() => CenterLabel.Text = StartDate.ToString(TitleLabelFormat)); 
       } 
       var start = CalendarStartDate; 
       var beginOfMonth = false; 
       var endOfMonth = false; 
       for (int i = 0; i < buttons.Count; i++) 
       { 
        endOfMonth |= beginOfMonth && start.Day == 1; 
        beginOfMonth |= start.Day == 1; 

        LstAttendanceDtl objAttendanceDtl = ListObjAttendanceTblList.Find(s => s.AttendanceDt.Equals(start.Date.ToString("dd/MM/yyyy"))); 
        string remarks = string.Empty; 

        if (i < 7 && WeekdaysShow && changes.HasFlag(CalandarChanges.StartDay)) 
        { 
         Device.BeginInvokeOnMainThread(() => labels[i].Text = start.ToString(WeekdaysFormat)); 
         //labels[i].Text = start.ToString(WeekdaysFormat); 
         //DateTime d = Convert.ToDateTime(objAttendanceDtl.AttendanceDt).Date; 
        } 
        if (changes.HasFlag(CalandarChanges.All)) 
        { 
         Device.BeginInvokeOnMainThread(()=>buttons[i].Text = string.Format("{0}", start.Day)); 
         //buttons[i].Text = string.Format("{0}", start.Day); 
        } 
        else 
        { 
         Device.BeginInvokeOnMainThread(() => buttons[i].TextWithoutMeasure = string.Format("{0}", start.Day)); 
        } 

        buttons[i].Date = start; 
        var isInsideMonth = beginOfMonth && !endOfMonth; 
        if (objAttendanceDtl != null) 
        { 
         remarks = objAttendanceDtl.Remark; 

         if ((remarks.ToLower()).Trim() == stringFullDay.ToLower().Trim()) 
         { 
          SetButtonPresent(buttons[i], isInsideMonth); 
         } 
         else if (remarks.ToLower().Trim() == stringAbsent.ToLower().Trim()) 
         { 
          SetButtonAbsent(buttons[i], isInsideMonth); 
         } 
         else if (remarks.ToLower().Trim() == stringWeekOff.ToLower().Trim()) 
         { 
          SetButtonWeekendMood(buttons[i], isInsideMonth); 
         } 
         else if (remarks.ToLower().Trim() == stringHolidays.ToLower().Trim()) 
         { 
          SetButtonHolidays(buttons[i], isInsideMonth); 
         } 
         else if (remarks.ToLower().Trim() == stringSecondhalfAbsent.ToLower().Trim() || 
          remarks.ToLower().Trim() == stringFirsthalfAbsent.ToLower().Trim()) 
         { 
          SetButtonHalfDayMood(buttons[i], isInsideMonth); 
         } 
         else 
         { 
          SetButtonDisabled(buttons[i]); 
         } 
        } 
        else 
        { 
         SetButtonOutSideMonth(buttons[i]); 
        } 
        SpecialDate sd = null; 
        if (SpecialDates != null) 
        { 
         sd = SpecialDates.FirstOrDefault(s => s.Date.Date == start.Date); 
        } 

        if (sd != null) 
        { 
         SetButtonSpecial(buttons[i], sd); 
        } 
        else if (SelectedDate.HasValue && start.Date == SelectedDate.Value.Date) 
        { 
         SetButtonSelected(buttons[i], isInsideMonth); 
        } 
        start = start.AddDays(1); 
       } 
      } 
      catch (Exception e) 
      { 

      } 
     } 

的問題是:

在 「Changecalendar」 功能,當我嘗試直接填寫標籤列表

labels[i].Text = start.ToString(WeekdaysFormat); 

它顯示我的錯誤

「UIKit的一致性錯誤:您所調用只能從UI線程調用的方法的UIKit」所以要去除這個錯誤,我寫

Device.BeginInvokeOnMainThread(() => labels[i].Text = start.ToString(WeekdaysFormat)); 

Device.BeginInvokeOnMainThread(()=>buttons[i].Text = string.Format("{0}", start.Day)); 

Device.BeginInvokeOnMainThread(() => buttons[i].TextWithoutMeasure = string.Format("{0}", start.Day)); 

,但它顯示我的錯誤

System.ArgumentOutOfRangeException:索引超出範圍。必須是非負數且小於集合的大小。

2.如果我把兩個功能「CallWebService」和「ChangeCalendar」在「FillCalendarWindow」一個接一個,然後列表對象未綁定和控制出來的功能,直接ChangeCalendar函數調用,並給我空參考對象。

+0

你想等到方法完成任務嗎? – Atul

+0

第一個函數是CallWebService,第二個函數是ChangeCalendar。完成第一個功能後應該調用第二個功能。但在我的情況下,在CallWebService()函數控件中並沒有去這行「If(response.flag == true)」(控件退出函數)並直接調用ChangeCalendar()方法。 –

回答

1

嘗試以下

protected async Task FillCalendarWindows() 
     { 
      try 
      { 
       for (int r = 0; r < 6; r++) 
       { 
        for (int c = 0; c < 7; c++) 
        { 
         if (r == 0) 
         { 
          labels.Add(new Label 
          { 
           HorizontalOptions = LayoutOptions.Center, 
           VerticalOptions = LayoutOptions.Center, 
           TextColor = Color.Black, 
           FontSize = 18, 
           FontAttributes = FontAttributes.Bold 
          }); 
          DayLabels.Children.Add(labels.Last(), c, r); 
         } 
         buttons.Add(new CalendarButton 
         { 
          BorderRadius = 0, 
          BorderWidth = BorderWidth, 
          BorderColor = BorderColor, 
          FontSize = DatesFontSize, 
          BackgroundColor = DatesBackgroundColor, 
          HorizontalOptions = LayoutOptions.FillAndExpand, 
          VerticalOptions = LayoutOptions.FillAndExpand 
         }); 
         buttons.Last().Clicked += DateClickedEvent; 
         MainCalendar.Children.Add(buttons.Last(), c, r); 
        } 
       } 
       flag = 1; 
       //Device.BeginInvokeOnMainThread(() => CallWebService(StartDate.Month, StartDate.Year)); 
       await CallWebService(StartDate.Month, StartDate.Year); 
       //CallServiceInNewTask(StartDate.Month, StartDate.Year); 
       //Device.BeginInvokeOnMainThread(() => await ChangeCalendar(CalandarChanges.All)); 

      } 
      catch (Exception e) 
      { 

      } 
     } 

你的web服務應該像

public async Task CallWebService(int Month, int Year) 
    { 
     try 
     { 
      var response = await GetResponseFromWebService.GetResponse<ServiceClasses.RootObject_AttendanceTable>(ServiceURL.GetAttendanceTableList + "Month=" + Month + "&Year=" + Year + "&EmpCd=" + _empCode); 
      if (response.Flag == true) 
      { 
       if (ListObjAttendanceTblList == null) 
       { 
        ListObjAttendanceTblList = new List<LstAttendanceDtl>(); 
       } 
       for (int i = 0; i < response.lstAttendanceDtl.Count; i++) 
       { 
        var objAttendanceTableList = new LstAttendanceDtl(); 

        objAttendanceTableList.AttendanceDt = response.lstAttendanceDtl[i].AttendanceDt; 
        objAttendanceTableList.EarlyDeparture = response.lstAttendanceDtl[i].EarlyDeparture; 
        objAttendanceTableList.InTime = response.lstAttendanceDtl[i].EarlyDeparture; 
        objAttendanceTableList.LateArrival = response.lstAttendanceDtl[i].EarlyDeparture; 
        objAttendanceTableList.OutTime = response.lstAttendanceDtl[i].OutTime; 
        objAttendanceTableList.OverTime = response.lstAttendanceDtl[i].OverTime; 
        objAttendanceTableList.Reason = response.lstAttendanceDtl[i].Reason; 
        objAttendanceTableList.Remark = response.lstAttendanceDtl[i].Remark; 
        objAttendanceTableList.Shift = response.lstAttendanceDtl[i].Shift; 
        objAttendanceTableList.WorkingHrs = response.lstAttendanceDtl[i].WorkingHrs; 

        ListObjAttendanceTblList.Add(objAttendanceTableList); 
       } 
      } 
      else 
      { 
      } 
      if (flag == 1) 
      { 
       await ChangeCalendar(CalandarChanges.All); 
      } 
      else 
      { 
       await ChangeCalendar(CalandarChanges.StartDate); 
      } 
     } 
     catch (WebException e) 
     { 

     } 
    } 

和你ChnageCalender方法應該是這樣

protected async Task ChangeCalendar(CalandarChanges changes) 
    { 
     try 
     { 
      if (changes.HasFlag(CalandarChanges.StartDate)) 
      { 
       Device.BeginInvokeOnMainThread(() => CenterLabel.Text = StartDate.ToString(TitleLabelFormat)); 
      } 
      var start = CalendarStartDate; 
      var beginOfMonth = false; 
      var endOfMonth = false; 
      for (int i = 0; i < buttons.Count; i++) 
      { 
       endOfMonth |= beginOfMonth && start.Day == 1; 
       beginOfMonth |= start.Day == 1; 

       LstAttendanceDtl objAttendanceDtl = ListObjAttendanceTblList.Find(s => s.AttendanceDt.Equals(start.Date.ToString("dd/MM/yyyy"))); 
       string remarks = string.Empty; 

       if (i < 7 && WeekdaysShow && changes.HasFlag(CalandarChanges.StartDay)) 
       { 
        Device.BeginInvokeOnMainThread(() => labels[i].Text = start.ToString(WeekdaysFormat)); 
        //labels[i].Text = start.ToString(WeekdaysFormat); 
        //DateTime d = Convert.ToDateTime(objAttendanceDtl.AttendanceDt).Date; 
       } 
       if (changes.HasFlag(CalandarChanges.All)) 
       { 
        Device.BeginInvokeOnMainThread(()=>buttons[i].Text = string.Format("{0}", start.Day)); 
        //buttons[i].Text = string.Format("{0}", start.Day); 
       } 
       else 
       { 
        Device.BeginInvokeOnMainThread(() => buttons[i].TextWithoutMeasure = string.Format("{0}", start.Day)); 
       } 

       buttons[i].Date = start; 
       var isInsideMonth = beginOfMonth && !endOfMonth; 
       if (objAttendanceDtl != null) 
       { 
        remarks = objAttendanceDtl.Remark; 

        if ((remarks.ToLower()).Trim() == stringFullDay.ToLower().Trim()) 
        { 
         SetButtonPresent(buttons[i], isInsideMonth); 
        } 
        else if (remarks.ToLower().Trim() == stringAbsent.ToLower().Trim()) 
        { 
         SetButtonAbsent(buttons[i], isInsideMonth); 
        } 
        else if (remarks.ToLower().Trim() == stringWeekOff.ToLower().Trim()) 
        { 
         SetButtonWeekendMood(buttons[i], isInsideMonth); 
        } 
        else if (remarks.ToLower().Trim() == stringHolidays.ToLower().Trim()) 
        { 
         SetButtonHolidays(buttons[i], isInsideMonth); 
        } 
        else if (remarks.ToLower().Trim() == stringSecondhalfAbsent.ToLower().Trim() || 
         remarks.ToLower().Trim() == stringFirsthalfAbsent.ToLower().Trim()) 
        { 
         SetButtonHalfDayMood(buttons[i], isInsideMonth); 
        } 
        else 
        { 
         SetButtonDisabled(buttons[i]); 
        } 
       } 
       else 
       { 
        SetButtonOutSideMonth(buttons[i]); 
       } 
       SpecialDate sd = null; 
       if (SpecialDates != null) 
       { 
        sd = SpecialDates.FirstOrDefault(s => s.Date.Date == start.Date); 
       } 

       if (sd != null) 
       { 
        SetButtonSpecial(buttons[i], sd); 
       } 
       else if (SelectedDate.HasValue && start.Date == SelectedDate.Value.Date) 
       { 
        SetButtonSelected(buttons[i], isInsideMonth); 
       } 
       start = start.AddDays(1); 
      } 
     } 
     catch (Exception e) 
     { 

     } 
    } 
+0

謝謝,我如何從正常的方法異步方法有點混淆。如何等待異步方法。你真的幫我。 –

+0

我很高興幫助你! – Atul

+0

最後一種方法不需要返回任務或等待。除非您使用'async'修飾符,否則此代碼不會編譯。 – valdetero

2

該問題未提供測試解決方案所需的完整源代碼。

回答有關在非異步方法中調用awaitable函數的問題。您可以使用

CallWebService().Wait(optional timeout); 

CallWebService().GetAwaiter().GetResult(); 

你也應該改變你的函數定義

async void CallWebService(int Month, int Year) 

async Task CallWebService(int Month, int Year); 

正確處理異常和線程切換

如果你確定調用CallWebService沒有再阻止你也可以做

CallWebService(1,2).ContinueWith((task) => 
{ 

}); 
1

我假設FillCalendarWindows()方法是從UI線程調用,但你不希望UI線程在外部操作GetResponseFromWebService.GetResponse發生時等待並凍結控件,這就是爲什麼您要在CallWebService()內部進行該異步調用的原因。

我認爲使用異步CallWebService更好的辦法是使用「異步一路」所以你必須改變所有的方法CallWebService上游到異步方法。由於async/await捕獲調用者的同步上下文,因此您將不需要執行Device.BeginInvokeOnMainThread,因此可以在UI線程上調用ChangeCalendar。

async void SomeEventHandler() 
{ 
// called from the UI thread (or its equivalent in Xamarin) 
    await FillCalendarWindows(); 
} 

protected async Task FillCalendarWindows() 
    { 
     try 
     { 
      //create 7*6 = 42 labels and buttons 

      await CallWebService(StartDate.Month, StartDate.Year); 

     } 
     catch (Exception e) 
     { 

     } 
    } 

public async Task CallWebService(int Month, int Year) 
    { 
     try 
     { 
      await GetResponseFromWebService.GetResponse... ; 

      // .... same code as in your example 

      ChangeCalendar(....); 

     } 
     catch /*... */ 
     { 

     } 
    } 

protected void ChangeCalendar(int changes) 
    { 
     try 
     { 
      /* no need to do Device.BeginInvokeOnMainThread() so you can replace all that with normal calls*/ 
     } 
     catch (Exception e) 
     { 
      /* ... */ 
     } 
    } 

不知道System.ArgumentOutOfRangeException如何得到待提高,我沒能在github正確的代碼版本,所以我不能夠調查特定的錯誤。我的猜測是你有多個線程修改「按鈕」集合,當你調用Device.BeginInvokeOnMainThread時,你可能會發現集合的元素少於預期。

TL; DR:使用異步/ AWAIT一路而不是調用異步方法以同步的方式,這應該更容易找出問題的原因

+0

謝謝,我在如何從正常方法異步方法有點混淆。如何等待異步方法。你真的幫我。 –

+0

這應該是答案,因爲它提供了一個更好的方法,實際上編譯而不是僅僅讓所有的任務都返回一個任務。 – valdetero

+0

你可能是對的,但是這並沒有提供關於如何使異步方法同步的答案。 –

0

我看到你的評論至少2個問題

  1. 「如果(response.flag ==真)(控制熄滅功能),並直接調用ChangeCalendar() - 顯然是因爲你不等待

  2. 你的數字按鈕( 42)與標籤數量(7)不一樣,所以當你t時ry使用相同的「i」標籤[i]和按鈕[i],您會得到標籤索引的ArgumentOutOfRangeException。註釋if(r==0)將標籤數量限制爲7。

     for (int r = 0; r < 6; r++) 
         { 
          for (int c = 0; c < 7; c++) 
          { 
           if (r == 0) 
           { 
            labels.Add(new Label