C# 在构造函数中运行async方法会停止显示数据的ObservableCollection
我在构造函数中调用异步方法时遇到了一个问题。它会停止数据在C# 在构造函数中运行async方法会停止显示数据的ObservableCollection,c#,wpf,async-await,task,C#,Wpf,Async Await,Task,我在构造函数中调用异步方法时遇到了一个问题。它会停止数据在可观测集合中的显示,即使我在调试中跟踪代码时可以看到它。为了解决这个问题,我有一个相同方法的非异步版本,但显然这并不理想。如何使我的异步方法在构造函数中正常工作 如果我在MainWindowViewModel的构造函数中调用this.RefreshCarList(“”),则随后调用this.RefreshCarListAsync(“”)(不是从构造函数中调用)将工作得非常好,并且数据会显示在屏幕上。如果我只调用this.RefreshCa
可观测集合中的显示,即使我在调试中跟踪代码时可以看到它。为了解决这个问题,我有一个相同方法的非异步版本,但显然这并不理想。如何使我的异步方法在构造函数中正常工作
如果我在MainWindowViewModel
的构造函数中调用this.RefreshCarList(“”)
,则随后调用this.RefreshCarListAsync(“”)
(不是从构造函数中调用)将工作得非常好,并且数据会显示在屏幕上。如果我只调用this.RefreshCarListAsync(“”)
,那么数据永远不会显示
public class MainWindowViewModel
{
private ObservableCollection<Car> carList;
public ICollectionView CarList { get; private set; }
private DataReceivedHandler dataReceivedHandler = new DataReceivedHandler();
public MainWindowViewModel()
{
//this.RefreshCarList(""); // Gets data on startup
this.RefreshCarListAsync("") // Doesn't show any data
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
}
public void RefreshCarList(string carBrand)
{
this.carList = this.dataReceivedHandler.GetCarList(carBrand);
}
public async Task RefreshCarListAsync(string carBrand)
{
this.carList = await this.dataReceivedHandler.GetCarListAsync(carBrand);
}
}
请注意,this.carList
在RefreshCarListAsync
中初始化:
this.carList = await this.dataReceivedHandler.GetCarListAsync(carBrand);
但它可能不是立即初始化,而是在GetCarListAsync
提供结果后初始化。然后,在构造函数中,您不需要等待RefreshCarListAsync
(无论如何,您不能在构造函数中执行此操作):
因为你没有等待——下一个声明
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
在初始化之前执行(可能)。carList
。因此,当该行执行时,this.carList
为空,很可能导致您的问题
因此,如果要从构造函数中执行此操作,则需要执行以下操作:
private async Task Initialize() {
try {
await this.RefreshCarListAsync("") // Doesn't show any data
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
}
catch (Exception ex) {
// do something meaningful, otherwise it will go unnoticed
}
}
从构造函数调用它。或者更好—公开它,不要从构造函数调用它,而是让使用viewmodel的任何对象调用它,因为它可能会等待它。如果在构造函数返回后动态设置属性,您应该在MainWindowViewModel
类中实现INotifyPropertyChanged
并引发PropertyChanged
事件:
public class MainWindowViewModel : INotifyPropertyChanged
{
private ICollectionView carList;
public ICollectionView CarList
{
get { return carList; }
private set { carList = value; NotifyPropertyChanged(); }
}
private DataReceivedHandler dataReceivedHandler = new DataReceivedHandler();
public async Task Initialise()
{
try
{
await this.CarListAsync("");
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
在构造函数中调用异步方法对我来说没有意义。它将允许您在构造函数完成之前使用对象,这可能是您的问题。为什么它必须是异步的?您不能从构造函数进行任何异步调用。考虑公开一个<代码>公共异步任务初始化()<代码>方法,在构建之后被调用和等待。是否<代码>这个?CarListAsync(“”)< /C>不返回一个不应该忽略的值吗?类似于carList=await CarListAsync(“”)代码>?另外,this.viewModel.Initialise()代码>应该是wait viewModel.Initialise()代码>从构造函数调用Initialize()
也很糟糕。应该等待它,但在构造函数中不能这样做。任何异步的东西都不属于这里。这就是为什么我添加了那么大的IF。若不是从构造函数调用,那个么它很有可能是从事件处理程序或其他无论如何都不能等待的地方调用的,因为这是UI框架。在这种情况下,很高兴知道您至少必须处理潜在的异常。我只是将Initialize方法公开,并在构建视图模型后调用并等待它。@Clemens我已尝试将Initialize方法公开,并执行Evk建议的代码,但仍然无法处理此错误,无法将类型ObservableCollection隐式转换为ICollectionViewWell,这是您的代码。然后将字段更改为ICollectionView
。关键是你应该实现INotifyPropertyChanged
。这就解决了这个问题。谢谢@mm8
this.RefreshCarListAsync("") // Doesn't show any data
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
private async Task Initialize() {
try {
await this.RefreshCarListAsync("") // Doesn't show any data
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
}
catch (Exception ex) {
// do something meaningful, otherwise it will go unnoticed
}
}
public class MainWindowViewModel : INotifyPropertyChanged
{
private ICollectionView carList;
public ICollectionView CarList
{
get { return carList; }
private set { carList = value; NotifyPropertyChanged(); }
}
private DataReceivedHandler dataReceivedHandler = new DataReceivedHandler();
public async Task Initialise()
{
try
{
await this.CarListAsync("");
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}