首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ObservationCollection,它使用支持WinRT & WP8/WinPRT的MVVM体系结构在ViewModel内部实现WinRT

ObservationCollection,它使用支持WinRT & WP8/WinPRT的MVVM体系结构在ViewModel内部实现WinRT
EN

Stack Overflow用户
提问于 2013-11-27 12:56:13
回答 1查看 1.6K关注 0票数 5

我的ViewModels在PCL内,因为我正在并行地开发Windows8.1和Windows应用程序。我的ViewModel中有一个ObservableCollection列表。

我在Windows8.1项目中的页面中有一个GridView。我希望从我的ViewModel中的内容列表中递增地加载项。通常,我会在ObservableCollection的自定义子类中实现ObservableCollection,但是,考虑到我的ViewModel在PCL中,ISupportIncrementalLoading是不可用的(WP8不支持它)。

因此,我的问题是,有没有人建议我如何在GridView的GridView绑定和我的ViewModel的可观察的Things属性之间创建某种转换器、适配器或抽象层,从而实现ISupportIncrementalLoading,然后调用ViewModel的LoadMoreThings方法并将项传递给GridView。

我觉得有一些解决方案,比如在我的视图模型中创建一个自定义的ISupportIncrementalLoading,然后将视图层委托给它。

谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-11-28 09:47:52

最后,我使用了抽象的工厂模式。事实是:

  • 您不能从PCL ViewModel层引用视图层,因为VM层不应该与视图层有关。这样做的好处之一是您可以创建ViewModel层的另一个使用者,而不依赖于目标平台。例如,在一个ViewModel库PCL项目的背面创建一个Windows8和Windows 8应用程序。
  • GridView是一个可以绑定到ObservableCollection<T>的WinRT组件。ObservableCollection<T>可以在视图层和ViewModel层中使用。如果您希望在应用程序中支持增量加载(对于大型数据集来说这是必需的),那么您需要创建一个实现ObservableCollection<T>的特殊子类来实现ISupportIncrementalLoading。我们要做的就是在ViewModel项目中创建这个子类,您就完成了。但是我们不能这样做,因为ISupportIncrementalLoading只在WinRT项目中可用。

这个问题可以通过抽象工厂模式来解决。ViewModel真正想要的只是一个ObservableCollection<T>,但是视图层需要一个实现ISupportIncrementalLoading的ObservableCollection。因此,答案是在ViewModel层中定义一个接口,让ViewModel准确地得到它想要的东西;让我们把它称为IPortabilityFactory。然后在视图层中定义一个IPortabilityFactory的具体实现,称为PortabilityFactory。使用视图层中的IoC将IPortabilityFactory (ViewModel接口)映射到PortabilityFactory (查看层具体文件)。

在ViewModel类的构造函数上,注入一个IPortabilityFactory实例。现在,ViewModel有了一个工厂,它将为它提供一个ObservableCollection<T>实例。

现在,不是在new ObservableCollection<Thing>()中调用ViewModel,而是调用factory.GetIncrementalCollection<Thing>(...)

好的,我们已经完成了ViewModel层;现在我们需要ObservableCollection<T>的自定义实现。它被称为IncrementalLoadingCollection,它在视图层中定义。它实现了ISupportIncrementalLoading

下面是代码和解释,以及ISupportIncrementalLoading的实现。

在ViewModel层中,我有一个抽象的工厂接口。

代码语言:javascript
复制
public interface IPortabilityFactory
{
    ObservableCollection<T> GetIncrementalCollection<T>(int take, Func<int, Task<List<T>>> loadMoreItems, Action onBatchStart, Action<List<T>> onBatchComplete);
}

在视图层(在本例中为Windows 8应用程序)中,我实现了这样一个具体工厂:

代码语言:javascript
复制
public class PortabilityFactory : IPortabilityFactory 
{
    public ObservableCollection<T> GetIncrementalCollection<T>(int take, Func<int, Task<List<T>>> loadMoreItems, Action onBatchStart, Action<List<T>> onBatchComplete)
    {
        return new IncrementalLoadingCollection<T>(take, loadMoreItems, onBatchStart, onBatchComplete);
    }
}

同样,在视图层中,我碰巧在我的IoC中使用了统一。创建IoC时,我将IPortabilityFactory (在PCL中)映射到PortabilityFactory (视图层;应用程序项目)。

代码语言:javascript
复制
Container.RegisterType<IPortabilityFactory, PortabilityFactory>(new ContainerControlledLifetimeManager());

现在我们需要创建一个ObservableCollection的子类,下面是代码:

代码语言:javascript
复制
public class IncrementalLoadingCollection<T> 
        : ObservableCollection<T>, ISupportIncrementalLoading
    {
        private Func<int, Task<List<T>>> _loadMoreItems = null;
        private Action<List<T>> _onBatchComplete = null;
        private Action _onBatchStart = null;


        /// <summary>
        /// How many records to currently skip
        /// </summary>
        private int Skip { get; set; }

        /// <summary>
        /// The max number of items to get per batch
        /// </summary>
        private int Take { get; set; }

        /// <summary>
        /// The number of items in the last batch retrieved
        /// </summary>
        private int VirtualCount { get; set; }

        /// <summary>
        /// .ctor
        /// </summary>
        /// <param name="take">How many items to take per batch</param>
        /// <param name="loadMoreItems">The load more items function</param>
        public IncrementalLoadingCollection(int take, Func<int, Task<List<T>>> loadMoreItems, Action onBatchStart, Action<List<T>> onBatchComplete)
        {
            Take = take;
            _loadMoreItems = loadMoreItems;
            _onBatchStart = onBatchStart;
            _onBatchComplete = onBatchComplete;
            VirtualCount = take;
        }

        /// <summary>
        /// Returns whether there are more items (if the current batch size is equal to the amount retrieved then YES)
        /// </summary>
        public bool HasMoreItems
        {
            get { return this.VirtualCount >= Take; }
        }

        public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
        {
           CoreDispatcher dispatcher = Window.Current.Dispatcher;
           _onBatchStart(); // This is the UI thread

           return Task.Run<LoadMoreItemsResult>(
                async () =>
                {
                    var result = await _loadMoreItems(Skip);
                    this.VirtualCount = result.Count;
                    Skip += Take;

                    await dispatcher.RunAsync(
                        CoreDispatcherPriority.Normal,
                        () =>
                        {
                            foreach (T item in result) this.Add(item);
                            _onBatchComplete(result); // This is the UI thread
                        });

                    return new LoadMoreItemsResult() { Count = (uint)result.Count };

                }).AsAsyncOperation<LoadMoreItemsResult>();
        }
    }

IncrementalLoadingCollection的构造函数要求获得由ViewModel通过工厂提供的四个参数:

  • 取-这是页码。
  • loadMoreItems --这是对ViewModel中将检索下一批项的函数的委托引用(重要的是,此函数不会在UI线程中运行)
  • onBatchStart --这将在调用loadMoreItems方法之前调用。这允许我对ViewModel上的属性进行可能影响视图的更改。例如,具有可观察的IsProcessing属性,该属性绑定到进度条的可见性属性。
  • onBatchComplete --这将在检索最新批处理并传入项之后调用。关键的是,这个函数将在UI线程上调用。

在ViewModel层中,我的ViewModel有一个构造函数,它接受IPortabilityFactory对象:

代码语言:javascript
复制
public const string IsProcessingPropertyName = "IsProcessing";

private bool _isProcessing = false;
public bool IsProcessing
{
    get
    {
        return _isProcessing;
    }
    set
    {
        if (_isProcessing == value)
        {
            return;
        }
        RaisePropertyChanging(IsProcessingPropertyName);
        _isProcessing = value;
        RaisePropertyChanged(IsProcessingPropertyName);
        }
}

    private IPortabilityFactory _factory = null;
    public ViewModel(IPortabilityFactory factory)
    {
        _factory = factory;
        Initialize();
    }


    private async void Initialize()
    {
        Things = _factory.GetIncrementalCollection<Thing>(10, LoadThings, 
           () => IsProcessing = true, BatchLoaded);
    }

    private void BatchLoaded(List<Thing> batch)
    {
        IsProcessing = false;
    }

    private async Task<List<Thing>> LoadThings(int skip)
    {
        var items = await _service.GetThings(skip, 10 /*page size*/);
        return items;
    }

我希望这能帮上忙。

票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20243139

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档