gpt4 book ai didi

xaml - ObservationCollection 使用 MVVM 架构在 PCL 内部的 ViewModel 中实现 ISupportIncrementalLoading,以支持 WinRT 和 WP8/WinPRT

转载 作者:行者123 更新时间:2023-12-04 16:34:21 26 4
gpt4 key购买 nike

我在 PCL 中有 ViewModel,因为我正在并行开发 Windows 8.1 和 Windows Phone 应用程序。我的 ViewModel 中有一个作为 ObservableCollection 的东西列表。

我在 Windows 8.1 项目的页面中有一个 GridView。我希望从我的 ViewModel 中的事物列表中逐步加载项目。通常我会在 ObservableCollection 的自定义子类中实现 ISupportIncrementalLoading,但是,鉴于我的 ViewModel 在 PCL 中,ISupportIncrementalLoading 不可用(WP8 不支持它)。

所以我的问题是,是否有人对我如何在 GridView 的 ItemsSource 绑定(bind)和我的 ViewModel 的 Observable Things 属性之间创建某种转换器、适配器或抽象层有任何建议,这将实现 ISupportIncrementalLoading 然后调用 ViewModel 的 LoadMoreThings方法并将项目传递给 GridView。

我觉得有一些解决方案,例如在我的 View Models PCL 中创建一个自定义 ISupportIncrementalLoading,然后让 View 层委托(delegate)给它。

谢谢

最佳答案

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

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

  • 这个问题可以通过使用抽象工厂模式来解决。 ViewModel 真正想要的只是 ObservableCollection<T> ,但 View 层需要一个实现 ISupportIncrementalLoading 的 ObservableCollection .所以答案是在 ViewModel 层中定义一个接口(interface),为 ViewModel 提供它想要的东西;我们就叫它 IPortabilityFactory .然后在View层定义 IPortabilityFactory的具体实现调用 PortabilityFactory .在 View 层使用 IoC 映射 IPortabilityFactory (ViewModel 界面)到 PortabilityFactory (查看层具体实现)。

    在 ViewModel 类的构造函数中,有一个 IPortabilityFactory实例注入(inject)。现在 ViewModel 有一个工厂,它将给它一个 ObservableCollection<T>实例。

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

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

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

    在 ViewModel 层 (PCL) 我有一个抽象工厂接口(interface)。
    public interface IPortabilityFactory
    {
    ObservableCollection<T> GetIncrementalCollection<T>(int take, Func<int, Task<List<T>>> loadMoreItems, Action onBatchStart, Action<List<T>> onBatchComplete);
    }

    在 View 层(本例中为 Windows 8 应用程序)中,我实现了一个像这样的具体工厂:
    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);
    }
    }

    同样,在 View 层中,我碰巧将 Unity 用于 IoC。创建 IoC 时,我将 IPortabilityFactory(在 PCL 中)映射到 PortabilityFactory(在 View 层;应用程序项目)。
    Container.RegisterType<IPortabilityFactory, PortabilityFactory>(new ContainerControlledLifetimeManager());

    我们现在需要创建 ObservableCollection 的子类,代码如下:
    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 通过工厂提供四个参数:
  • take - 这是页面大小
  • loadMoreItems - 这是 ViewModel 中一个函数的委托(delegate)引用,它将检索下一批项目(重要的是,这个函数不会在 UI 线程中运行)
  • onBatchStart - 这将在调用 loadMoreItems 方法之前被调用。这允许我对可能影响 View 的 ViewModel 上的属性进行更改。例如,有一个可观察的 IsProcessing 属性,该属性绑定(bind)到进度条的 Visibility 属性。
  • onBatchComplete - 这将在检索最新批处理并传入项目后立即调用。至关重要的是,此函数将在 UI 线程上调用。

  • 在 ViewModel 层,我的 ViewModel 上有一个构造函数,它接受一个 IPortabilityFactory 对象:
    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;
    }

    我希望这可以帮助别人。

    关于xaml - ObservationCollection 使用 MVVM 架构在 PCL 内部的 ViewModel 中实现 ISupportIncrementalLoading,以支持 WinRT 和 WP8/WinPRT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20243139/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com