C# 如何从非异步方法调用异步方法?
我以xamarin的形式工作。我正在尝试在日历控件中绑定Web服务。有关日历控件(XamForms.Controls.calendar),请参阅以下链接 第一个功能是创建7*6=42个标签和按钮,然后使用“callWebService”方法调用服务功能,这是从服务获取响应的异步方法C# 如何从非异步方法调用异步方法?,c#,xamarin,xamarin.ios,xamarin.android,xamarin.forms,C#,Xamarin,Xamarin.ios,Xamarin.android,Xamarin.forms,我以xamarin的形式工作。我正在尝试在日历控件中绑定Web服务。有关日历控件(XamForms.Controls.calendar),请参阅以下链接 第一个功能是创建7*6=42个标签和按钮,然后使用“callWebService”方法调用服务功能,这是从服务获取响应的异步方法 protected void FillCalendarWindows() { try { for (int r = 0
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)
{
}
}
它向我显示了一个错误
“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”中一个接一个的列表对象没有绑定,控件从函数中出来,直接更改Calendar函数调用并给我空引用对象。该问题没有提供测试解决方案所需的完整源代码 回答您关于在非异步方法中调用等待函数的问题。你可以用
CallWebService().Wait(optional timeout);
或
您还应该更改函数定义
async void CallWebService(int Month, int Year)
到
正确处理异常和线程切换
如果您可以在不阻塞的情况下调用CallWebService,那么您也可以这样做
CallWebService(1,2).ContinueWith((task) =>
{
});
该问题没有提供测试解决方案所需的完整源代码 回答您关于在非异步方法中调用等待函数的问题。你可以用
CallWebService().Wait(optional timeout);
或
您还应该更改函数定义
async void CallWebService(int Month, int Year)
到
正确处理异常和线程切换
如果您可以在不阻塞的情况下调用CallWebService,那么您也可以这样做
CallWebService(1,2).ContinueWith((task) =>
{
});
我假设FillCalendarWindows()方法是从UI线程调用的,但您不希望UI线程在外部操作GetResponseFromWebService.GetResponse发生时等待并冻结控件,这就是您在CallWebService()中等待异步调用的原因 我认为使用异步CallWebService的更好方法是使用“async all-way”,因此您必须将CallWebService上游的所有方法更改为异步方法。这还有一个额外的好处,即您不需要执行Device.beginInvokeMainThread,因为async/await捕获调用方的同步上下文,因此将在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上找到正确的代码版本,因此无法调查该特定错误。我猜您有多个线程在修改“buttons”集合,当您调用Device.BeginInvokeOnMainThread时,您可能会发现集合中的元素比预期的少
TL;DR:始终使用async/await,而不是以同步方式调用async方法,这将更容易找到问题的原因方法从UI线程调用,但您不希望UI线程在外部操作GetResponseFromWebService.GetResponse发生时等待并冻结控件,这就是您在CallWebService()中等待异步调用的原因 我认为使用异步CallWebService的更好方法是使用“async all-way”,因此您必须将CallWebService上游的所有方法更改为异步方法。这还有一个额外的好处,即您不需要执行Device.beginInvokeMainThread,因为async/await捕获调用方的同步上下文,因此将在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上找到正确的代码版本,因此无法调查该特定错误。我猜您有多个线程在修改“buttons”集合,当您调用Device.BeginInvokeOnMainThread时,您可能会发现集合中的元素比预期的少
TL;DR:始终使用async/await,而不是以同步方式调用async方法,这将更容易找到问题的原因我从您的评论中看到至少两个问题
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
for(int r=0;r<6;r++)
{
对于(int c=0;c<7;c++)
{
如果(r==0)
{
标签。添加(新标签)
我从你的评论中看到至少两个问题
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
for(int r=0;r<6;r++)
{
对于(int c=0;c<7;c++)
{
如果(r==0)
{
标签。添加(新标签)
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)
{
}
}
受保护的异步任务FillCalendarWindows()
{
尝试
{
对于(int r=0;r<6;r++)
{
对于(int c=0;c<7;c++)
{
如果(r==0)
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)
{
}
}
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)
{
}
}