5

ViewModels'i bir PCL içinde kullanıyorum çünkü bir Windows 8.1 ve Windows Phone uygulamasını paralel olarak geliştiriyorum. ViewModel'imde Gözlemlenebilir Bir Veri Olarak bir şeyler listesi var.GözlemCollection ViewModel içinde ViewModel içinde WinRT & WP8/WinPRT desteği için MVVM mimarisini kullanarak uygulayan GözlemCollection

Windows 8.1 projesinde bir Sayfa içinde GridView var. ViewModel'imdeki öğeler listemdeki öğeleri aşamalı olarak yüklemek istiyorum. Normalde, ISupportIncrementalLoading'i, ObservableCollection özel bir alt sınıfında uygulardım, ancak ViewModel'im bir PCL içinde olduğu için, ISupportIncrementalLoading kullanılamıyor (WP8 tarafından desteklenmiyor).

Benim sorum şu ki, herhangi bir dönüştürücü, bağdaştırıcı veya soyutlama katmanı nasıl GridView ve benim ViewModel Gözlemlenebilir Şeyler özelliği arasında ISupportIncrementalLoading uygular ve sonra da bir tür dönüştürücü, bağdaştırıcı veya soyutlama katmanı oluşturmak için herhangi bir öneri var mı? ViewModel'in LoadMoreThings yöntemini çağırın ve öğeleri GridView'e iletin.

Görünüm Modeller PCL'de özel bir ISupportIncrementalLoading oluşturma ve daha sonra View layer temsilcisine sahip olmak gibi bir çözüm varmış gibi hissediyorum.

teşekkürler

cevap

16

Sonuçta, soyut fabrika desenini kullandım. gerçekler: Sen PCL ViewModel katmandan Görünüm katmanı referans yapamaz

  • VM tabakası Görünüm katmanla ilgili edilmemelidir olarak. Bunun faydalarından biri de, hedef platformda herhangi bir bağımlılık olmadan ViewModel katmanının başka bir tüketicisini yaratabilmenizdir. Örneğin. Bir ViewModel kütüphanesi PCL projesinin arkasında bir Windows 8 ve Windows Phone 8 uygulaması oluşturun.

  • GridView, ObservableCollection<T>'a bağlanabilen bir WinRT bileşenidir. ObservableCollection<T>hem Görünüm katmanında hem de ViewModel katmanında kullanılabilir. Uygulamanız içinde artan yüklemeyi desteklemek istiyorsanız (büyük veri kümeleri için bir zorunluluktur), ISupportIncrementalLoading'u uygulayan ObservableCollection<T> özel bir alt sınıf oluşturmanız gerekir. 'un olmasını istediğimiz, yalnızca bu alt sınıfı ViewModel projesinin içinde oluşturuyor ve işiniz bitti. Ancak bunu yapamayız çünkü ISupportIncrementalLoading yalnızca bir WinRT projesinde kullanılabilir.

Bu sorun, soyut fabrika kalıbı kullanılarak çözülebilir. Tüm ViewModel'ın gerçekten istediği ObservableCollection<T>'dur, ancak Görünüm katmanı, ISupportIncrementalLoading'u uygulayan bir GözlemlenebilirKoleksiyon gerektirir. Bu nedenle, ViewModel katmanında istediği şeyi veren ViewModel katmanında bir arabirim tanımlamak; IPortabilityFactory diyelim. Ardından Görünüm katmanında PortabilityFactory olarak adlandırılan IPortabilityFactory somut bir uygulama tanımlayın. IPortabilityFactory (ViewModel arabirimi) PortabilityFactory (Görünüm katmanı beton impl.) Alanına eşlemek için Görünüm katmanında bir IoC kullanın.

ViewModel sınıfının yapıcısı üzerinde, IPortabilityFactory örneğinin enjekte edilmesi gerekir. Şimdi ViewModel, bir ObservableCollection<T> örneğini verecek bir fabrikaya sahip.

Artık ViewModel'de new ObservableCollection<Thing>() numaralı telefonu aramak yerine factory.GetIncrementalCollection<Thing>(...) numaralı telefonu arayın.

Tamam, bu yüzden ViewModel katmanı ile işimiz bitti; şimdi ObservableCollection<T>'un özel uygulamasına ihtiyacımız var. Bu, IncrementalLoadingCollection olarak adlandırılır ve Görünüm katmanında tanımlanmıştır. ISupportIncrementalLoading uygular.

ISupportIncrementalLoading uygulamasıyla birlikte kod ve açıklamaları burada bulabilirsiniz.

ViewModel katmanında (PCL) Soyut bir fabrika arayüzüne sahibim. Görünüm tabakasının içine, benim IoC için Unity kullanmak olur, Yine

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

: Görünüm katmanında

public interface IPortabilityFactory 
{ 
    ObservableCollection<T> GetIncrementalCollection<T>(int take, Func<int, Task<List<T>>> loadMoreItems, Action onBatchStart, Action<List<T>> onBatchComplete); 
} 

(bu durumda, Windows 8 uygulaması,) Böyle bir beton fabrikası uygulamak . IoC oluşturulduğunda, IPortabilityFactory'yi (PCL'de) PortabilityFactory'ye (Görünüm katmanında; uygulama projesinde) eşleştiriyorum.

Container.RegisterType<IPortabilityFactory, PortabilityFactory>(new ContainerControlledLifetimeManager()); 
Şimdi ObservableCollection bir alt sınıfını oluşturmak için gereken ve burada kod

:

    :

    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 en yapıcı fabrikasında aracılığı ViewModel tarafından tedarik edilecek dört parametre sorar

  • almak - Bu sayfa boyutunda.

  • loadMoreItems - Bu

  • onBatchStart (önemlisi, bu fonksiyon UI iş parçacığı içine yayınlanmaz) öğelerin sonraki toplu alır ViewModel içinde bir işleve bir temsilci referanstır - bu sadece loadMoreItems önce çağrılır yöntem denir. Bu, ViewModel'deki Görünüm'ü etkileyebilecek özelliklerde değişiklik yapmamı sağlar. örneğin, bir ilerleme çubuğunun Görünürlük özelliğine bağlı olan gözlemlenebilir bir IsProcessing özelliğine sahiptir.

  • onBatchComplete - Bu, son toplu işin alınmasından hemen sonra çağrılacak ve öğeleri içeri aktarılacaktır. Önemli olan, bu işlev UI iş parçacığı üzerinde çağrılacaktır.

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

    bu kimse yardımcı olur umarım: ViewModel katmanında

, benim ViewModel bir IPortabilityFactory nesnesini kabul Üzerinde bir kurucuya sahip.