运行 构造函数中的异步方法停止显示数据的 ObservableCollection
Running async method in constructor stops ObservableCollection showing data
我在构造函数中调用异步方法时遇到问题。它停止显示在 ObservableCollection
中的数据,即使我在跟踪代码时可以在调试中看到它。为了解决这个问题,我有一个相同方法的非异步版本,但显然这并不理想。如何让我的异步方法在构造函数中正常工作?
如果我在 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);
}
}
视图模型使用从服务获取数据的数据接收器class:
public class DataReceivedHandler
{
private CarDataService dataService = new CarDataService();
private List<Car> carList = new List<Car>();
private ObservableCollection<Car> carOC = new ObservableCollection<Car>();
public ObservableCollection<Car> GetCarList(string carBrand)
{
carListFromService = this.dataService.GetCarList(carBrand);
this.carOC.Clear();
foreach (ICar car in carListFromService)
this.carOC.Add(car);
return (this.carOC);
}
public async Task<ObservableCollection<Car>> GetCarListAsync(string carBrand)
{
carListFromService = await Task.Run(() => this.dataService.GetCarList(carBrand)).ConfigureAwait(false);
this.carOC.Clear();
foreach (ICar car in carListFromService)
this.carOC.Add(car);
return (this.carOC);
}
}
服务:
public class CarDataService
{
private List<Car> CarList = new CarList();
public List<Car> GetCarList(string carBrand)
{
return this.CarList;
}
}
更新:
所以我试过这个作为建议的答案之一,但它仍然不起作用:
public async Task Initialise()
{
try
{
await this.CarListAsync("");
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
this.viewModel.Initialise(); // in a different class
注意this.carList
在RefreshCarListAsync
中初始化:
this.carList = await this.dataReceivedHandler.GetCarListAsync(carBrand);
但它可能不会立即初始化,而是稍后在 GetCarListAsync
提供结果时初始化。然后在构造函数中你不等待 RefreshCarListAsync
(无论如何你不能在构造函数中这样做):
this.RefreshCarListAsync("") // Doesn't show any data
因为你没有等待-下一个语句
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
执行(可能)在 this.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
}
}
并从构造函数中调用它。或者更好 - 让它成为 public 并且不要从构造函数调用它但让任何使用你的视图模型来调用它,因为它有可能等待它。
如果在构造函数返回后动态设置 属性,您应该实施 INotifyPropertyChanged
并在 MainWindowViewModel
[=16= 中引发 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));
}
}
我在构造函数中调用异步方法时遇到问题。它停止显示在 ObservableCollection
中的数据,即使我在跟踪代码时可以在调试中看到它。为了解决这个问题,我有一个相同方法的非异步版本,但显然这并不理想。如何让我的异步方法在构造函数中正常工作?
如果我在 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);
}
}
视图模型使用从服务获取数据的数据接收器class:
public class DataReceivedHandler
{
private CarDataService dataService = new CarDataService();
private List<Car> carList = new List<Car>();
private ObservableCollection<Car> carOC = new ObservableCollection<Car>();
public ObservableCollection<Car> GetCarList(string carBrand)
{
carListFromService = this.dataService.GetCarList(carBrand);
this.carOC.Clear();
foreach (ICar car in carListFromService)
this.carOC.Add(car);
return (this.carOC);
}
public async Task<ObservableCollection<Car>> GetCarListAsync(string carBrand)
{
carListFromService = await Task.Run(() => this.dataService.GetCarList(carBrand)).ConfigureAwait(false);
this.carOC.Clear();
foreach (ICar car in carListFromService)
this.carOC.Add(car);
return (this.carOC);
}
}
服务:
public class CarDataService
{
private List<Car> CarList = new CarList();
public List<Car> GetCarList(string carBrand)
{
return this.CarList;
}
}
更新:
所以我试过这个作为建议的答案之一,但它仍然不起作用:
public async Task Initialise()
{
try
{
await this.CarListAsync("");
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
this.viewModel.Initialise(); // in a different class
注意this.carList
在RefreshCarListAsync
中初始化:
this.carList = await this.dataReceivedHandler.GetCarListAsync(carBrand);
但它可能不会立即初始化,而是稍后在 GetCarListAsync
提供结果时初始化。然后在构造函数中你不等待 RefreshCarListAsync
(无论如何你不能在构造函数中这样做):
this.RefreshCarListAsync("") // Doesn't show any data
因为你没有等待-下一个语句
this.CarList = new QueryableCollectionView(this.carList, typeof(Car));
执行(可能)在 this.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
}
}
并从构造函数中调用它。或者更好 - 让它成为 public 并且不要从构造函数调用它但让任何使用你的视图模型来调用它,因为它有可能等待它。
如果在构造函数返回后动态设置 属性,您应该实施 INotifyPropertyChanged
并在 MainWindowViewModel
[=16= 中引发 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));
}
}