我正在从XML文件反序列化对象列表,并希望绑定到View中这些对象的实际内容,并通过ViewModel传递。问题是文件操作是async
,这一直到ViewModel,其中Property getter不能被标记为......
我将文件夹中的所有XML文件反序列化为Profile
个对象,并将它们存储在List<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;
}
然后我的ViewModel中的绑定属性理想地调用这样的静态方法
public async Task<ObservableCollection<string>> Lists
{
get
{
return new ObservableCollection<string>(GetAllProfiles().Select(p => p.Name));
}
}
但无法将属性标记为async
public ObservableCollection<string> Lists
{
get
{
return new ObservableCollection<string>((GetAllProfiles().Result).Select(p => p.Name));
}
}
await folder.GetFilesAsync()
通话中阻止)调用async
Initialize()方法,将GetProfiles()
函数的结果加载到变量中,然后进行NotifyPropertyChanged("Lists")
调用:
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来执行某些线程同步操作。 - 必须等待Initialize方法,并且ctors不能异步,所以这种模式本质上是无用的。
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
}
}
答案 0 :(得分:1)
属性不能是异步的,所以这个解决方案不会像你提到的那样工作。 Task.Result等待任务完成,但是这会阻止I / O操作的异步回调返回的UI线程,因此您的应用程序会死锁,因为永远不会调用回调。您的解决方案确实是最好的方法。它可以改进。