Data binding WinRT ViewModel数据绑定到异步方法
我正在对XML文件中的对象列表进行反序列化,并希望通过ViewModel绑定到视图中这些对象的实际内容。问题是文件操作是异步的,这会一直冒泡到ViewModel,在ViewModel中属性getter不能被标记为异步的 问题Data binding WinRT ViewModel数据绑定到异步方法,data-binding,mvvm,asynchronous,viewmodel,windows-runtime,Data Binding,Mvvm,Asynchronous,Viewmodel,Windows Runtime,我正在对XML文件中的对象列表进行反序列化,并希望通过ViewModel绑定到视图中这些对象的实际内容。问题是文件操作是异步的,这会一直冒泡到ViewModel,在ViewModel中属性getter不能被标记为异步的 问题 我将文件夹中的所有XML文件反序列化为Profile对象,并将它们存储在列表中。此方法(必须)标记为async public static async Task<List<Profile>> GetAllProfiles() {
- 我将文件夹中的所有XML文件反序列化为
对象,并将它们存储在Profile
列表中。此方法(必须)标记为
async
public static async Task<List<Profile>> GetAllProfiles() { DataContractSerializer ser = new DataContractSerializer(typeof(Profile)); StorageFolder folder = await ApplicationData.Current.RoamingFolder.CreateFolderAsync("Profiles", CreationCollisionOption.OpenIfExists); List<Profile> profiles = new List<Profile>(); foreach (var f in await folder.GetFilesAsync()) { var fs = await f.OpenStreamForReadAsync(); profiles.Add((Profile)ser.ReadObject(fs)); fs.Dispose(); } return profiles; }
- 但这永远不会执行(由于某种原因,它会阻塞
调用)await文件夹.getfileasync()
Initialize()方法,该方法在变量中加载async
函数的结果,然后进行GetProfiles()
调用:NotifyPropertyChanged(“列表”)
public ViewModel() { Initialize(); } public async void Initialize() { _profiles = await Profile.GetAllProfiles(); NotifyPropertyChanged("Lists"); } private List<Profile> _profiles; public ObservableCollection<string> Lists { get { if (_profiles != null) return new ObservableCollection<string>(_profiles.Select(p => p.Name)); else return null; } }
问题: 有更好的办法吗? 是否有我尚未发现的模式/方法 编辑 在执行非UI代码时会出现问题的根源,您不能依赖NotifyPropertyChanged来执行某些线程同步工作。-必须等待方法初始化,并且CTOR不能是异步的,所以本质上这是一种无用的模式公共视图模型() { 初始化(); } 公共异步void Initialize() { _profiles=等待Profile.GetAllProfiles(); NotifyPropertyChanged(“列表”); } 私人名单(个人资料),; 公共可观测收集列表 { 得到 { 如果(_profiles!=null) 返回新的observeCollection(_profiles.Select(p=>p.Name)); 其他的 返回null; } }
public MyClass() { Initialize(); } public async void Initialize() { _profiles = await Profile.GetAllProfiles(); } private ObservableCollection<Profile> _profiles; public ObservableCollection<string> Lists { get { return _profiles; // this will always be null } }
属性不能是异步的,因此此解决方案不会像您提到的那样工作。Result等待任务完成,但这会阻塞I/O操作的异步回调返回的UI线程,因此您的应用程序处于死锁状态,因为从未调用回调。你的解决方案确实是最好的方法。不过,它还可以改进publicmyclass() { 初始化(); } 公共异步void Initialize() { _profiles=等待Profile.GetAllProfiles(); } 私有可观察收集_配置文件; 公共可观测收集列表 { 得到 { return _profiles;//这将始终为空 } }
- 您应该将_profiles字段设置为ObservableCollection,这样就不需要每次访问列表时都将列表转换为OC
- 由于您执行的I/O操作可能需要任意的时间,因此您应该在执行过程中启用某种进度指示器
- 在某些情况下,您可能希望Lists属性更懒惰,并且只在第一次访问Init方法时调用它
public ViewModel() { Initialize(); } public async void Initialize() { _profiles = await Profile.GetAllProfiles(); NotifyPropertyChanged("Lists"); } private List<Profile> _profiles; public ObservableCollection<string> Lists { get { if (_profiles != null) return new ObservableCollection<string>(_profiles.Select(p => p.Name)); else return null; } }
public MyClass() { Initialize(); } public async void Initialize() { _profiles = await Profile.GetAllProfiles(); } private ObservableCollection<Profile> _profiles; public ObservableCollection<string> Lists { get { return _profiles; // this will always be null } }
- 但这永远不会执行(由于某种原因,它会阻塞