我正在反序列化 XML 文件中的对象列表,并希望通过 ViewModel 绑定到我的视图中这些对象的实际内容。问题是文件操作是这样的async
,并且这一直冒泡到 ViewModel,其中属性 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; }
理想解决方案 1
然后,我的 ViewModel 中的绑定属性将理想地调用该静态方法,如下所示
public async Task<ObservableCollection<string>> Lists { get { return new ObservableCollection<string>(GetAllProfiles().Select(p => p.Name)); } }
但是属性不能被标记
async
理想方案2
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
}
}