Tuesday, September 17, 2013

Date Virtualization with Caliburn.Micro Controls

Data virtualization is a great way to lazy load your item lists when you can have a huge number of items. To utilize data virtualization with Caliburn.Micro, you'll need to use a special class that takes the input from the list and generates the control.

FeedViewModel.cs

 private readonly Func<FeedItemViewModel> _createFeedItem;  
 public FeedViewModel(Func<FeedItemViewModel> createFeedItem)  
 {  
   _createFeedItem = createFeedItem;
   LoadFeedItems();  
 }  
 private VirtualControlList<FeedInfo, FeedItemViewModel> _feedItems;  
 public VirtualControlList<Media, FeedItemViewModel> FeedItems  
 {  
   get { return _feedItems; }  
   set  
   {  
     if (_feedItems != value)  
     {  
       _feedItems = value;  
       NotifyOfPropertyChange(() => FeedItems);  
     }  
   }  
 }  
 void LoadFeedItems()  
 {  
   IList<FeedInfo> feedInfo = GetFeedInfoFromSomewhere();  
   FeedItems = new VirtualControlList<FeedInfo, FeedItemViewModel>(feedInfo, (f) =>  
   {  
     var feedItem = _createFeedItem();  
     feedItem.SetFeedInfo(f);  
     return feedItem;  
   });  
 }  

FeedView.xaml

 <ItemsControl x:Name="FeedItems" VirtualizingStackPanel.VirtualizationMode="Standard" Margin="12,22,13,0" Height="480">  
       <ItemsControl.ItemTemplate>  
         <DataTemplate>  
           <views:FeedItemView cal:Bind.Model="{Binding}" />  
         </DataTemplate>  
       </ItemsControl.ItemTemplate>  
       <ItemsControl.ItemsPanel>  
         <ItemsPanelTemplate>  
           <VirtualizingStackPanel Orientation="Vertical" CanVerticallyScroll="True">  
           </VirtualizingStackPanel>  
         </ItemsPanelTemplate>  
       </ItemsControl.ItemsPanel>  
       <ItemsControl.Template>  
         <ControlTemplate TargetType="ItemsControl">  
           <ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Hidden">  
             <ItemsPresenter/>  
           </ScrollViewer>  
         </ControlTemplate>  
       </ItemsControl.Template>  
     </ItemsControl>  

VirtualControlList.cs

 using InstaFeed.ViewModels;  
 using InstaSharp.Model;  
 using System;  
 using System.Collections;  
 using System.Collections.Generic;  
 using System.Diagnostics;  
 public class VirtualControlList<Input, ControlType> : IList<ControlType>, IList  
 {  
   private IList<Input> _source = null;  
   private Func<Input, ControlType> _createControl;  
   public VirtualControlList(IList<Input> source, Func<Input,ControlType> createControl)  
   {  
     _source = source;  
     _createControl = createControl;  
   }  
   #region IList<MediaFeed> Members  
   public int IndexOf(ControlType item)  
   {  
     throw new NotImplementedException();  
   }  
   public void Insert(int index, ControlType item)  
   {  
     throw new NotImplementedException();  
   }  
   public void RemoveAt(int index)  
   {  
     throw new NotImplementedException();  
   }  
   public ControlType this[int index]  
   {  
     get  
     {  
       throw new NotImplementedException();  
     }  
     set  
     {  
       throw new NotImplementedException();  
     }  
   }  
   #endregion  
   #region ICollection<MediaFeed> Members  
   public void Add(ControlType item)  
   {  
     throw new NotImplementedException();  
   }  
   public void Clear()  
   {  
     throw new NotImplementedException();  
   }  
   public bool Contains(ControlType item)  
   {  
     throw new NotImplementedException();  
   }  
   public void CopyTo(ControlType[] array, int arrayIndex)  
   {  
     throw new NotImplementedException();  
   }  
   /// <summary>  
   /// Return the total number of items in your list.  
   /// </summary>  
   public int Count  
   {  
     get  
     {  
       return _source.Count;  
     }  
   }  
   public bool IsReadOnly  
   {  
     get { throw new NotImplementedException(); }  
   }  
   public bool Remove(ControlType item)  
   {  
     throw new NotImplementedException();  
   }  
   #endregion  
   #region IEnumerable<Output> Members  
   public IEnumerator<ControlType> GetEnumerator()  
   {  
     throw new NotImplementedException();  
   }  
   #endregion  
   #region IEnumerable Members  
   System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()  
   {  
     throw new NotImplementedException();  
     //for (int i = 0; i < Count; ++i)  
     //{  
     //  yield return new MediaFeed();  
     //}  
   }  
   #endregion  
   #region IList Members  
   object IList.this[int index]  
   {  
     get  
     {  
       // here is where the magic happens, create/load your data on the fly.  
       Debug.WriteLine("Requsted item " + index.ToString());  
       var feedItem = _createControl(_source[index]);  
       return feedItem;  
     }  
     set  
     {  
       throw new NotImplementedException();  
     }  
   }  
   public int Add(object value)  
   {  
     throw new NotImplementedException();  
   }  
   public bool Contains(object value)  
   {  
     throw new NotImplementedException();  
   }  
   public int IndexOf(object value)  
   {  
     throw new NotImplementedException();  
   }  
   public void Insert(int index, object value)  
   {  
     throw new NotImplementedException();  
   }  
   public bool IsFixedSize  
   {  
     get { throw new NotImplementedException(); }  
   }  
   public void Remove(object value)  
   {  
     throw new NotImplementedException();  
   }  
   #endregion  
   #region ICollection Members  
   public void CopyTo(Array array, int index)  
   {  
     throw new NotImplementedException();  
   }  
   public bool IsSynchronized  
   {  
     get { throw new NotImplementedException(); }  
   }  
   public object SyncRoot  
   {  
     get { throw new NotImplementedException(); }  
   }  
   #endregion  
 }