我有一个 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/