WinRT的视图模型的DataBind到异步方法(WinRT ViewModel DataBind

2019-09-20 23:43发布

我从一个XML文件反序列化对象的列表,并希望结合在我看来,这些对象的实际内容,在经过一个视图模型。 问题是,文件操作是async和这个气泡一路攀升到视图模型,其中地产干将不能被标记为这样的...

问题

  • 我反序列化所有的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必须等待并构建函数不能异步,所以essentialy这是图案是无用的。

    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
        }
    }

Answer 1:

属性不能异步所以你提到的这个方法是行不通的。 Task.Result等待完成的任务,但是这是阻止您的UI线程在I / O操作的异步回调的回报,所以你死锁您的应用程序,因为回调永远不会被调用。 您的解决方案确实是最好的方式。 它可以改善,虽然。

  • 你应该把_profiles领域一个ObservableCollection,这样你就不会需要列表中每个被访问列表的时间转换为OC。
  • 既然要执行,可以采取任意时间量的I / O操作 - 您应该启用某种进度指示器,而它是在进步。
  • 在某些情况下,你可能需要的名单属性为懒惰和只调用init方法的第一次访问。


文章来源: WinRT ViewModel DataBind to async method