2016-10-24 4 views
0

Я работаю в форме xamarin. Я пытаюсь связать веб-службу в управлении календаря. обратитесь к ссылке для управления календарем (XamForms.Controls.Calendar).Как вызвать метод async из метода не async?

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) 
      { 

      } 
     } 

Проблемы:

1. В функции "Changecalendar", когда я пытаюсь заполнить список ярлыков непосредственно

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

он показывает мне ошибку

«UIKit Консистенция ошибка:. Вы вызываете метод 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) 
      { 

      } 
     } 

Ваш Webservice должен быть как

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

Спасибо, я немного запутался в том, как асинхронный метод из обычного метода. Как подождать метод async. Вы действительно помогаете мне. –

+0

Я рад помочь вам! – Atul

+0

Последний метод не должен возвращать задачу или ждать. Этот код не будет компилироваться, если вы не используете модификатор 'async'. – valdetero

2

Вопрос не содержит полный исходный код, необходимый для проверки решения.

Отвечая на ваш вопрос о вызове ожидаемой функции в не асинхронном методе.Вы можете использовать

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() метод вызывается из потока пользовательского интерфейса, но вы не хотите, чтобы поток пользовательского интерфейса для подождите и заморозить элемент управления, пока выполняется внешняя операция GetResponseFromWebService.GetResponse, и именно поэтому вы ожидаете этого асинхронного вызова внутри CallWebService().

Я думаю, что лучший способ использования async CallWebService - использовать «async all the way», поэтому вам придется изменить все методы выше по течению CallWebService на методы async. Это имеет дополнительное преимущество, которое вам не нужно делать Device.BeginInvokeOnMainThread, так как async/await захватывает контекст синхронизации вызывающего, поэтому 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: использование асинхронного/ОЖИДАНИЕ всего пути вместо вызова метода асинхронного в синхронизации таким образом, это должно сделать его легче найти причину проблемы

+0

Спасибо, я немного запутался в том, как асинхронный метод от обычного метода. Как подождать метод async. Вы действительно помогаете мне. –

+0

Это должен быть ответ, поскольку он обеспечивает лучший подход и фактически компилирует вместо того, чтобы просто заставить все вернуть задачу. – valdetero

+0

Возможно, вы правы, но это не дает ответа на то, как синхронизировать методы async. –

0

Я вижу, по крайней мере, 2 проблемы с ваших комментариев

  1. «Если (response.flag == TRUE) (управление выходит из функции) и непосредственно вызывать ChangeCalendar(). - очевидно, потому что вы не ждете

  2. Вашего количество кнопок (42) не совпадает с числом меток (7), поэтому, когда вы t ry to go labels [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 
    
Смежные вопросы