C# 异步等待继续未按预期工作
我正在开发一个C# 异步等待继续未按预期工作,c#,wpf,multithreading,asynchronous,async-await,C#,Wpf,Multithreading,Asynchronous,Async Await,我正在开发一个wpfprism应用程序。我有一个delgate命令,它负责填充一个ObservableCollection,该集合由UI线程使用async和wait以异步方式拥有。集合依次绑定到图表 为了使集合能够被多个线程访问,我启用了同步,如下所示: BindingOperations.EnableCollectionSynchronization(ChartBoundCollection, _lock); private async void ShowPatientVisitsV
wpfprism
应用程序。我有一个delgate命令
,它负责填充一个ObservableCollection
,该集合由UI线程使用async和wait以异步方式拥有。集合依次绑定到图表
为了使集合能够被多个线程访问
,我启用了同步
,如下所示:
BindingOperations.EnableCollectionSynchronization(ChartBoundCollection, _lock);
private async void ShowPatientVisitsVsDays()
{
IsChartBeingPopulated = true;
this.ChartSubTitle = "Requests Vs Days";
this.SeriesTitle = "Days";
ChartBoundCollection.Clear();
await ShowRequestsVsDaysAsync();
IsChartBeingPopulated = false;
}
private async Task ShowRequestsVsDaysAsync()
{
await Task.Run(() =>
{
if (PatientVisits.Count() > 0)
{
var days = PatientVisits.Select(p => p.VisitDate.Value.Date).Distinct();
foreach (var i in days)
{
var dayVisitCount = PatientVisits.Where(p => p.VisitDate.Value.Date == i).Count();
ChartBoundCollection.Add(new PatientVisitVsXAxis() { XAxis = i.ToShortDateString(), NumberOfPatientVisits = dayVisitCount });
}
}
});
}
命令处理程序逻辑如下所示:
BindingOperations.EnableCollectionSynchronization(ChartBoundCollection, _lock);
private async void ShowPatientVisitsVsDays()
{
IsChartBeingPopulated = true;
this.ChartSubTitle = "Requests Vs Days";
this.SeriesTitle = "Days";
ChartBoundCollection.Clear();
await ShowRequestsVsDaysAsync();
IsChartBeingPopulated = false;
}
private async Task ShowRequestsVsDaysAsync()
{
await Task.Run(() =>
{
if (PatientVisits.Count() > 0)
{
var days = PatientVisits.Select(p => p.VisitDate.Value.Date).Distinct();
foreach (var i in days)
{
var dayVisitCount = PatientVisits.Where(p => p.VisitDate.Value.Date == i).Count();
ChartBoundCollection.Add(new PatientVisitVsXAxis() { XAxis = i.ToShortDateString(), NumberOfPatientVisits = dayVisitCount });
}
}
});
}
填充可观察集合的逻辑如下所示:
BindingOperations.EnableCollectionSynchronization(ChartBoundCollection, _lock);
private async void ShowPatientVisitsVsDays()
{
IsChartBeingPopulated = true;
this.ChartSubTitle = "Requests Vs Days";
this.SeriesTitle = "Days";
ChartBoundCollection.Clear();
await ShowRequestsVsDaysAsync();
IsChartBeingPopulated = false;
}
private async Task ShowRequestsVsDaysAsync()
{
await Task.Run(() =>
{
if (PatientVisits.Count() > 0)
{
var days = PatientVisits.Select(p => p.VisitDate.Value.Date).Distinct();
foreach (var i in days)
{
var dayVisitCount = PatientVisits.Where(p => p.VisitDate.Value.Date == i).Count();
ChartBoundCollection.Add(new PatientVisitVsXAxis() { XAxis = i.ToShortDateString(), NumberOfPatientVisits = dayVisitCount });
}
}
});
}
我面临的问题是,在设置wait的异步方法完成后,我正在设置的continuationischartbeingpluded=false
没有被执行
await ShowRequestsVsDaysAsync();
因此,甚至在异步方法之前就设置了ischartbeingpluded
完成了
await ShowRequestsVsDaysAsync();
单击将调用命令处理程序ShowPatientVisitsVsDays()
在视图上单击按钮。该按钮绑定到以下项:
命令:
ischartbeingpluded
用于设置属于“扩展WPF ToolKit”的BusyDiator
控件的isBusyDependencyProperty
。
这样做的目的是在绑定集合中填充图表数据时显示BusyIndicator
<xctk:BusyIndicator IsBusy="{Binding Path=IsChartBeingPopulated}" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<chart:ClusteredColumnChart Grid.Row="0" ChartTitle="Patient Visits History" ChartSubTitle="{Binding Path=ChartSubTitle}">
<chart:ClusteredColumnChart.Series>
<chart:ChartSeries SeriesTitle="{Binding Path=SeriesTitle}" DisplayMember="XAxis" ValueMember="NumberOfPatientVisits" ItemsSource="{Binding Path=ChartBoundCollection}" />
</chart:ClusteredColumnChart.Series>
</chart:ClusteredColumnChart>
</Grid>
</xctk:BusyIndicator>
不确定问题出在哪里。有人知道这是什么原因吗?你可以这样做
private async void ShowPatientVisitsVsDays()
{
IsChartBeingPopulated = true;
this.ChartSubTitle = "Requests Vs Days";
this.SeriesTitle = "Days";
new ChartBoundCollection().Clear();
IsChartBeingPopulated = await ShowRequestsVsDaysAsync();//here we are waiting till the async method is finished.
}
private async Task<bool> ShowRequestsVsDaysAsync()
{
return await Task.Run(() =>
{
if (PatientVisits.Any())//replace Count with Any to avoid unwanted enumerations.
{
var days = PatientVisits.Select(p => p.VisitDate.Value.Date).Distinct();
foreach (var i in days)
{
var dayVisitCount = PatientVisits.Count(p => p.VisitDate.Value.Date == i);
chartBoundCollection.Add(new PatientVisitVsXAxis() { XAxis = i.ToShortDateString(), NumberOfPatientVisits = dayVisitCount });
}
}
Thread.Sleep(5000);//this is for testing. Sleep the thread for 5secs. Now your busyIndicator must be visible for 5secs minimum.
return false;//return false, so that we can use it to populate IsChartBeingPopulated
});
}
您没有同步对集合的访问<代码>绑定操作。EnableCollectionSynchronization
不会神奇地使收集线程安全。它只确保数据绑定引擎在不获取锁的情况下不会枚举集合
添加和清除集合时,仍然需要锁定\u lock
对象
有关
启用采集同步
的更多信息,请参阅。您是否应该将ShowPatientVisitsVsDays
类型更改为Task,并等待ShowPatientVisitsVsDays
调用,以使异步状态趋于平稳?谢谢您的评论。我无法更改ShowPatientVisitsVsDays的返回类型,因为它是一个命令处理程序。类似的情况可能是异步处理按钮的单击事件,在这种情况下,您也不能更改事件处理程序的签名以返回任务。@lovecoding:您想告诉我,showRequestsVsdayAsync
调用没有等待吗?此外,由于showRequestSvsdaySync
不包含异步代码,您应该将其同步并包装到任务中。在ShowPatientVisitsVsDays
中运行
@Kosala:我已经尝试了您建议的方法,但奇怪的是,等待直到异步方法完成才发生。您能告诉我们如何调用showtpatientvisitsvsdays
以及ischartbeingpluded
的用法吗?我用Busy指示器测试了一个类似的代码,它正在工作。我添加了Thread.Sleep(5000)代码>到代码。现在,您的忙碌状态必须至少显示5秒钟。刚才注意到您已将ObservableCollection用于ChartBoundCollection
。原因是什么?每次向异步方法内的集合添加新项时,它都会通知UI。这是您想要的还是应该在添加所有值后才刷新?如果是这样,将其更改为List.Agreed,添加Thread.Sleep会显示忙碌指示器。此外,我还需要绑定到图表的ObservableCollection,因为集合的内容将在运行时根据图表上上下文菜单项的单击进行修改。困扰我的问题是等待并没有像预期的那样起作用。理想情况下,它应该让异步方法完成,然后执行延续,即等待之后的代码行,该行将IsChartBeingPopulated设置为false。