c# - 如何使我的构造函数在 UWP MVVM 模型中异步? (MVVM Lighttoolkit)

标签 c# asynchronous uwp mvvm-light windows-community-toolkit

我有一个 UWP 项目想要读取 StorageFolder VideosLibrary 并在带有缩略图的 View 中显示 mp4 文件列表。

使用 MVVM ligth 工具包,我用 xaml 设置了这 4 只苍蝇。 Xaml 使用 UWP 社区工具包包装面板。

1)ViewModelLocator.cs

namespace UWP.ViewModels
{
/// <summary>
/// This class contains static reference to all the view models in the 
/// application and provides an entry point for the bindings.
/// </summary>

class ViewModelLocator
{
    /// <summary>
    /// Initializes a new instance of the ViewModelLocator class.
    /// </summary>
    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
        if (ViewModelBase.IsInDesignModeStatic)
        {
            // Create  design time view services and models
        }
        else
        {
            // Create run Time view services and models
        }
        //Register services used here

        SimpleIoc.Default.Register<VideoListModel>();
    }


    public VideoListModel VideoListModel
    {
        get { return ServiceLocator.Current.GetInstance<VideoListModel>(); 
    }
}
}

2) VideoListItem.cs

namespace UWP.Models
{
class VideoListItem : ViewModelBase
{
    public string VideoName { get; set; }
    public string Author { get; set; }
    public Uri Vid_url { get; set; }
    public BitmapImage Image { get; set; }

    public VideoListItem(string videoname,string author,Uri url, BitmapImage img)
    {
        this.VideoName = videoname;
        this.Author = author;
        this.Vid_url = url;
        this.Image = img;
    }
}
}

3) VideoListModel.cs

namespace UWP.ViewModels
{
class VideoListModel : ViewModelBase
{
    public ObservableCollection<VideoListItem> VideoItems { get; set; }

    private VideoListItem videoItems;

    public VideoListModel()
    {

    }

    public async static Task<List<VideoListItem>> GetVideoItem()
    {
        List<VideoListItem> videoItems = new List<VideoListItem>();
        StorageFolder videos_folder = await KnownFolders.VideosLibrary.CreateFolderAsync("Videos");
        var queryOptions = new QueryOptions(CommonFileQuery.DefaultQuery, new[] { ".mp4" });
        var videos = await videos_folder.CreateFileQueryWithOptions(queryOptions).GetFilesAsync();


        foreach (var video in videos)
        {
            //Debug.WriteLine(video.Name);
            //videoItems.Add(new VideoListItem());
            var bitmap = new BitmapImage();
            var thumbnail = await video.GetThumbnailAsync(ThumbnailMode.SingleItem);
            await bitmap.SetSourceAsync(thumbnail);
            videoItems.Add(new VideoListItem(video.DisplayName, "", new Uri(video.Path),bitmap));

        }

        //foreach(var video in videoItems)
        //{
        //    Debug.WriteLine("Name:{0} , Author:{1}, Uri:{2}, Bitmap:{3}", video.VideoName, video.Author, video.Vid_url, video.Image.UriSource);
        //}


        return videoItems;
    }


}
}

4) 视频.xaml

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="using:UWP.Views"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:Controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
  x:Class="UWP.Views.Video"
  mc:Ignorable="d"
  NavigationCacheMode="Enabled"
  DataContext="{Binding Source={StaticResource ViewModelLocator},Path=VideoListModel}">
<!--NavigationCacheMode Enable for the page state save-->
<Page.Resources>
    <DataTemplate x:Key="VideoTemplate">
        <Grid Width="{Binding Width}"
              Height="{Binding Height}"
              Margin="2">
            <Image HorizontalAlignment="Center"
                   Stretch="UniformToFill"
                   Source="{Binding Image}" />
            <TextBlock Text="{Binding VideoName}"/>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Author" />
                <TextBlock Text="{Binding Author}" />
            </StackPanel>
        </Grid>
    </DataTemplate>
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView Name="VideosListWrapPanal"
              ItemTemplate="{StaticResource VideoTemplate}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Controls:WrapPanel />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ListView>

</Grid>
</Page>

我想在我的构造函数的 VideoListModel 中做类似下面的事情。

public async MainViewModel()
{
   VideoItems = new ObservableCollection<MainMenuItem>(await GetVideoItem());

}

如何以异步方式完成此初始化? 为了获取缩略图,我创建了 GetVideoItem() 方法, 但是我找不到在构造函数中异步调用 GetVideoItem 的方法。 有谁知道如何解决这个任务?

最佳答案

简短的回答是:你不能使构造函数async

但是有一些选项可以解决这个问题。这里有两个建议:

解决方案一:ViewModel 生命周期

很多 MVVM Frameworks 使用 lifecylce 方法来解决这个问题。您可以添加 ActivateAsync 方法,该方法在实例化 ViewModel 后由您的框架调用。

在您的示例中,这可以在您的 ViewModelLocator 中完成。

interface IActivate
{
    Task ActivateAsync();
}

// Call it like this:
(model as IActivate)?.ActivateAsync(); // this will work even if the model does not implement IActivate

解决方案 2:使用工厂

另一种选择是使用工厂方法 来创建ViewModel工厂方法 可以获取所有async 数据,并在所有数据聚合后创建对象。

public static async Task<CustomViewModel> Create()
{
    var data = await FetchAsyncData();
    return new CustomViewModel(data);
}

示例:

这里是关于如何使用 activate 模式的简短片段。

public class ViewModelLocator 
{
    // existing implementation goes here

    public async Task<TViewModel> Create<TViewodel>
    {
        var model = ServiceLocator.Current.GetInstance<TViewodel>(); 
        var activate = model as IActivate;
        if(activate != null)
            await activate.ActivateAsync();

        return model;
    }
}

现在工厂方法只返回一个完全激活的模型。这种模式的优点是创建者不需要知道它正在创建的模型。它检查模型是否需要激活并调用它。然后可以将所有激活逻辑放在 ViewModel 中。

关于c# - 如何使我的构造函数在 UWP MVVM 模型中异步? (MVVM Lighttoolkit),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46168674/

相关文章:

C# 二进制搜索变体

c# - 如何在 UWP 中使用 C# dll

c# - Azure 移动应用身份验证

c# - 如何在 Windows Phone 8 Tile 上运行数字时钟?(内有说明)

c# - 如何在异步方法中以同步方式更新 UI 线程上的元素?

c++ - boost::async - 不确定实现

javascript - 没有为 async.parallel 调用完整的回调

iphone - 为什么我的 UITableView 在异步重新加载数据期间滚动时会失去流动性?

listview - UWP 更改 ListView 项目高度

c# - 给定当前角度和目标位置计算目标角度?