On Demand Data Loading in XamGrid and XamDataTree

[Infragistics] Mihail Mateev / Wednesday, February 2, 2011

 Loading data on demand is typical of applications that use hierarchical data. The article “On Demand Data Loading in XamTree” demonstrated an application using Infragistics XamTree. This article shows how they could benefit from hierarchical data XamGrid and XamDataTree as load only the data that is necessary to show.

Requirements:

  1. NetAdvantage for Silverlight  Line of Business 2010 Vol.3
  2. NetAdvantage for .NET 2010 Vol.3
  3. NetAdvantage Ultimate 2010 Vol.3

 

Sample data:

Demo application uses a sample data from XML file.
Sample application uses the same like the data from the article “On Demand Data Loading in XamTree” 

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <books>
   3:   <book Title="The Elegant Universe" Author="Brian Greene" UnitPrice="15.95" Url="http://www.amazon.com/Elegant-Universe-Superstrings-Dimensions-Ultimate/dp/0393046885" ReleaseDate="02/01/1999" >
   4:     <chapter Title="Tied Up with String" />
   5:     <chapter Title="Space, Time, and the Eye of the Beholder" />
   6:     <chapter Title="Of Warps and Ripples" />
   7:     <chapter Title="Microscopic Weirdness" />
   8:     <chapter Title="The Need for a New Theory: General Relativity vs. Quantum Mechanics" />
   9:     <chapter Title="Nothing but Music: The Essentials of Superstring Theory" />
  10:     <chapter Title="The &quot;Super&quot; in Superstrings" />
  11:     <chapter Title="More Dimensions Than Meet the Eye" />
  12:     <chapter Title="The Smoking Gun: Experimental Signatures" />
  13:     <chapter Title="Quantum Gravity" />
  14:     <chapter Title="Tearing the Fabric of Space" />
  15:     <chapter Title="Beyond Strings: In Search of M-Theory" />
  16:     <chapter Title="Black Holes: A String/M-Theory Perspective" />
  17:     <chapter Title="Reflections on Cosmology" />
  18:     <chapter Title="Prospects" />
  19:   </book>
  20:  
  21:   <book Title="Dive Into Python" Author="Mark Pilgrim" UnitPrice="39.99" Url="http://www.amazon.com/Dive-Into-Python-Mark-Pilgrim/dp/1590593561" ReleaseDate="07/19/2004" >
  22:     <chapter Title="Installing Python" />
  23:     <chapter Title="Your First Python Program" />
  24:     <chapter Title="Native Datatypes" />
  25:     <chapter Title="The Power of Introspection" />
  26:     <chapter Title="Objects and Object-Orientation" />
  27:     <chapter Title="Exceptions and File Handling" />
  28:     <chapter Title="Regular Expressions" />
  29:     <chapter Title="HTML Processing" />
  30:     <chapter Title="XML Processing" />
  31:     <chapter Title="Scripts and Streams" />
  32:     <chapter Title="HTTP Web Services" />
  33:     <chapter Title="SOAP Web Services" />
  34:     <chapter Title="Unit Testing" />
  35:     <chapter Title="Test-First Programming" />
  36:     <chapter Title="Refactoring" />
  37:     <chapter Title="Functional Programming" />
  38:     <chapter Title="Dynamic Functions" />
  39:     <chapter Title="Performance Tuning" />
  40:   </book>
  41:  
  42:   <book Title="The Selfish Gene (30th Anniversary Edition)" Author="Richard Dawkins" UnitPrice="15.95" Url="http://www.amazon.com/Selfish-Gene-Anniversary-Introduction/dp/0199291152" ReleaseDate="05/25/2006" >
  43:     <chapter Title="Why are people?" />
  44:     <chapter Title="The replicators" />
  45:     <chapter Title="Immortal coils" />
  46:     <chapter Title="The gene machine" />
  47:     <chapter Title="Aggression: stability and the selfish machine" />
  48:     <chapter Title="Genesmanship" />
  49:     <chapter Title="Family planning" />
  50:     <chapter Title="Battle of the generations" />
  51:     <chapter Title="Battle of the sexes" />
  52:     <chapter Title="You scratch my back, I'll ride on yours" />
  53:     <chapter Title="Memes: the new replicators" />
  54:     <chapter Title="Nice guys finish first" />
  55:     <chapter Title="The long reach of the gene" />
  56:   </book>
  57:  
  58:   <book Title="The Ideological Origins of the American Revolution (Enlarged Edition)" Author="Bernard Bailyn" UnitPrice="24.00" Url="http://www.amazon.com/Ideological-Origins-American-Revolution/dp/0674443020" ReleaseDate="03/01/1992" >
  59:     <chapter Title="The Literature of Revolution" />
  60:     <chapter Title="Sources and Traditions" />
  61:     <chapter Title="Power and Liberty: A Theory of Politics" />
  62:     <chapter Title="The Logic of Rebellion" />
  63:     <chapter Title="Transformation" />
  64:     <chapter Title="The Contagions of Liberty" />
  65:     <chapter Title="Fulfillment: A Commentary on the Constitution" />
  66:   </book>
  67:  
  68:   <book Title="Gödel, Escher, Bach: an Eternal Golden Braid" Author="Douglas R. Hofstadter" UnitPrice="20.00" Url="http://www.amazon.com/Godel-Escher-Bach-Douglas-Hofstadter/dp/B001IAM392" ReleaseDate="01/01/1999" >
  69:     <chapter Title="The MU-puzzle." />
  70:     <chapter Title="Meaning and Form in Mathematics." />
  71:     <chapter Title="Figure and Ground." />
  72:     <chapter Title="Consistency, Completeness, and Geometry." />
  73:     <chapter Title="Recursive Structures and Processes." />
  74:     <chapter Title="The Location of Meaning." />
  75:     <chapter Title="The Propositional Calculus." />
  76:     <chapter Title="Typographical Number Theory." />
  77:     <chapter Title="Mumon and Gödel." />
  78:     <chapter Title="Levels of Description, and Computer Systems." />
  79:     <chapter Title="Brains and Thoughts." />
  80:     <chapter Title="Minds and Thoughts." />
  81:     <chapter Title="BlooP and FlooP and GlooP." />
  82:     <chapter Title="On Formally Undecidable Propositions of TNT and Related Systems." />
  83:     <chapter Title="Jumping out of the System." />
  84:     <chapter Title="Self-Ref and Self-Rep." />
  85:     <chapter Title="Church, Turing, Tarski, and Others." />
  86:     <chapter Title="Artificial Intelligence: Retrospects." />
  87:     <chapter Title="Artificial Intelligence: Prospects." />
  88:     <chapter Title="Strange Loops, Or Tangled Hierarchies." />
  89:   </book>
  90:  
  91:   <book Title="Silverlight 1.0" Author="Devin Rader, Jason Beres, J. Ambrose Little, Grant Hinkson" UnitPrice="23.37" Url="http://www.amazon.com/Silverlight-1-0-Devin-Rader/dp/0470228407" ReleaseDate="10/29/2007" >
  92:    <chapter Title="Introduction to Silverlight" />
  93:     <chapter Title="Building Silverlight Applications Using XAML" />
  94:     <chapter Title="Designing Silverlight Applications Using Expression Blend 2"  />
  95:     <chapter Title="Coding Silverlight Applications with JavaScript and XAML"  />
  96:     <chapter Title="Using Silverlight with ASP.NET"  />
  97:     <chapter Title="Silverlight 1.1 and the CLR"  />
  98:     <chapter Title="Video Player: Silverlight 1.0 Case Example"  />
  99:   </book>
 100:   <book Title="Harry Potter and the Deathly Hallows" Author="J. K. Rowling" UnitPrice="20.99" Url="http://www.amazon.com/Harry-Potter-Deathly-Hallows-Book/dp/0545010225" ReleaseDate="07/21/2007" />
 101:   <book Title="Silverlight 2 Silverlight 2 Programmer's Reference's Reference" Author="J. Ambrose Little, Jason Beres, Grant Hinkson, Devin Rader, Joe Croney" UnitPrice="31.49" Url="http://www.amazon.com/Silverlight-Programmers-Reference-Ambrose-Little/dp/0470385405" ReleaseDate="03/23/2009" />
 102:   <book Title="Breaking Dawn (The Twilight Saga, Book 4)" Author="Stephenie Meyer" UnitPrice="12.64" Url="http://www.amazon.com/New-Moon-Twilight-Saga-Book/dp/0316024961" ReleaseDate="08/02/2008" />
 103:   <book Title="The Last Lecture" Author="Randy Pausch and Jeffrey Zaslow" UnitPrice="13.17" Url="http://www.amazon.com/Last-Lecture-Randy-Pausch/dp/1401323251" ReleaseDate="04/08/2008" />
 104:   <book Title="Brisingr" Author="Christopher Paolini" UnitPrice="16.50" Url="http://www.amzon.com/Brisingr-Inheritance-Book-Christopher-Paolini/dp/0375826726" ReleaseDate="09/20/2008" />
 105:   <book Title="The Story of Edgar Sawtelle" Author="David Wroblewski" UnitPrice="14.27" Url="http://www.amazon.com/Story-Edgar-Sawtelle-Novel-Oprah/dp/0061768065" ReleaseDate="09/19/2008"  />
 106:   <book Title="The Tales of Beedle the Bard" Author="J. K. Rowling" UnitPrice="7.14" Url="http://www.amazon.com/Tales-Beedle-Bard-Standard/dp/0545128285" ReleaseDate="12/04/2008" />
 107:   <book Title="The Appeal" Author="John Grisham " UnitPrice="18.45" Url="http://www.amazon.com/Appeal-John-Grisham/dp/0385515049" ReleaseDate="01/29/2008" />
 108:   <book Title="When You Are Engulfed in Flames" Author="David Sedaris" UnitPrice="15.59" Url="http://www.amazon.com/When-You-Are-Engulfed-Flames/dp/0316143472" ReleaseDate="06/03/2008" />
 109:   <book Title="In Defense of Food: An Eater's Manifesto" Author="Michael Pollan" UnitPrice="13.17" Url="http://www.amazon.com/Defense-Food-Eaters-Manifesto/dp/1594201455" ReleaseDate="01/01/2008" />
 110:   <book Title="The Revolution: A Manifesto" Author="Ron Paul" UnitPrice="13.17" Url="http://www.amazon.com/Host-Novel-Stephenie-Meyer/dp/031606804" ReleaseDate="04/01/2008" />
 111:   <book Title="The Host: A Novel" Author="Stephenie Meyer " UnitPrice="13.17" Url="http://www.amazon.com/Host-Novel-Stephenie-Meyer/dp/031606804" ReleaseDate="05/06/2008" />
 112:   <book Title="The Post-American World" Author="Fareed Zakaria" UnitPrice="17.13" Url="http://www.amazon.com/Post-American-World-Fareed-Zakaria/dp/039306235X" ReleaseDate="05/05/2008" />
 113:   <book Title="Hungry Girl" Author="Lisa Lillien" UnitPrice="12.21" Url="http://www.amazon.com/Hungry-Girl-Survival-Strategies-Guilt-Free/dp/0312377428" ReleaseDate="04/29/2008" />
 114:   <book Title="Fearless Fourteen (Stephanie Plum, No. 14)" Author="Janet Evanovich" UnitPrice="18.45" Url="http://www.amazon.com/Fearless-Fourteen-Stephanie-Plum-No/dp/0312349513" ReleaseDate="06/17/2008" />
 115:   <book Title="The Tales of Beedle the Bard, Collector's Edition" Author="J. K. Rowling" UnitPrice="100.00" Url="http://www.amazon.com/Beedle-Collectors-Offered-Exclusively-Amazon/dp/0956010903" ReleaseDate="12/04/2008" />
 116:   <book Title="Unaccustomed Earth" Author="Jhumpa Lahiri" UnitPrice="16.50" Url="http://www.amazon.com/Unaccustomed-Earth-Jhumpa-Lahiri/dp/0307265730" ReleaseDate="04/01/2008" />
 117:   <book Title="sTORI Telling" Author="Tori Spelling" UnitPrice="16.47" Url="http://www.amazon.com/sTORI-Telling-Tori-Spelling/dp/1416950737" ReleaseDate="03/11/2008" />
 118:   <book Title="Audition: A Memoir" Author="Barbara Walters" UnitPrice="19.77" Url="http://www.amazon.com/Audition-Memoir-Barbara-Walters/dp/030726646X"  ReleaseDate="05/06/2008" />
 119: </books>

 

Steps to reproduce:

  • Download sample data
  • Create a sample Silverlight Navigation Application, hosted in an ASP.Net application.
  • Imeplement a Silverlight-enabled WCF service that returns collections of book and book chapters.
  • Create in the Silverlight application a  MVVM using for data custom collections that inherits VirtualCollection<T>

WCF Service implementation:
WCF service implementation is almost the same like in the article:  “On Demand Data Loading in XamTree” 

Create a new Silverlight-enabled WCF service, named BookDataSourceService :

  

BookDataSourceService implementation:

   1: #region BookDataSourceService
   2: [ServiceContract(Namespace = "")]
   3: [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
   4: public class BookDataSourceService
   5: {
   6:  
   7:     #region Member Variables
   8:  
   9:     static string dataPath = HttpContext.Current.Server.MapPath(".") + Path.DirectorySeparatorChar +
  10:    ConfigurationManager.AppSettings["DataDirectory"] + Path.DirectorySeparatorChar +
  11:                    ConfigurationManager.AppSettings["DataFile"];
  12:  
  13:     static XDocument doc = XDocument.Load(dataPath);
  14:  
  15:     #region GetBookCount
  16:     [OperationContract]
  17:     public int GetBookCount()
  18:     {
  19:         try
  20:         {
  21:             return doc.Descendants("book").Count();
  22:         }
  23:         catch (Exception)
  24:         {
  25:             return 0;
  26:         }
  27:     }
  28:     #endregion //GetBookCount
  29:  
  30:  
  31:     #endregion //Member Variables
  32:  
  33:     #region Methods
  34:  
  35:     #region GetBooks
  36:     /// <summary>
  37:     /// Gets the books.
  38:     /// </summary>
  39:     /// <returns></returns>
  40:     private static IEnumerable<Book> GetBooks()
  41:     {
  42:         //Return books as IEnumerable
  43:         if (doc != null)
  44:         {
  45:  
  46:             var dataSource = (from d in doc.Descendants("book")
  47:                               where (d.Descendants("chapter") != null || d.Descendants("chapter").Count() >= 0)
  48:                               select new Book
  49:                               {
  50:                                   Author = d.Attribute("Author").Value,
  51:                                   Title = d.Attribute("Title").Value,
  52:                                   UnitPrice = d.Attribute("UnitPrice").GetDecimalValue(),
  53:                                   Url = d.Attribute("Url").Value,
  54:                                   ReleaseDate = d.Attribute("ReleaseDate").Value,
  55:                                   ChaptersCount = d.Descendants("chapter").Count()
  56:                               });
  57:  
  58:             return dataSource.ToList();
  59:         }
  60:         return null;
  61:     }
  62:  
  63:     /// <summary>
  64:     /// Gets the books.
  65:     /// </summary>
  66:     /// <param name="startIndex">The start index.</param>
  67:     /// <param name="itemsCount">The items count.</param>
  68:     /// <returns></returns>
  69:     private static IEnumerable<Book> GetBooks(int startIndex, int itemsCount)
  70:     {
  71:         //Return range of books as IEnumerable
  72:         if (doc != null)
  73:         {
  74:  
  75:             var dataSource = (from d in doc.Descendants("book")
  76:                               where (d.Descendants("chapter") != null || d.Descendants("chapter").Count() >= 0)
  77:                               select new Book
  78:                               {
  79:                                   Author = d.Attribute("Author").Value,
  80:                                   Title = d.Attribute("Title").Value,
  81:                                   UnitPrice = d.Attribute("UnitPrice").GetDecimalValue(),
  82:                                   Url = d.Attribute("Url").Value,
  83:                                   ReleaseDate = d.Attribute("ReleaseDate").Value,
  84:                                   ChaptersCount = d.Descendants("chapter").Count(),
  85:                               });
  86:  
  87:  
  88:             List<Book> lst = dataSource.ToList();
  89:  
  90:             itemsCount = Math.Min(lst.Count - 1 - startIndex, itemsCount);
  91:  
  92:             return lst.GetRange(startIndex, itemsCount);
  93:         }
  94:         return null;
  95:     }
  96:     #endregion //GetBooks
  97:  
  98:     #region GetChapters
  99:  
 100:     /// <summary>
 101:     /// Gets the chapters.
 102:     /// </summary>
 103:     /// <param name="url">The URL.</param>
 104:     /// <returns></returns>
 105:     private static IEnumerable<Chapter> GetChapters(string url)
 106:     {
 107:         //Return the chapters for a specified book
 108:         if (doc != null)
 109:         {
 110:             var chapters = (from d in doc.Descendants("book")
 111:                             where
 112:                                 (d.Attribute("Url").Value.Equals(url) && d.Descendants("chapter") != null &&
 113:                                  d.Descendants("chapter").Count() > 0)
 114:                             select GetChapters(d));
 115:  
 116:             return chapters.First().ToList();
 117:         }
 118:  
 119:         return null;
 120:     }
 121:  
 122:     /// <summary>
 123:     /// Gets the chapters.
 124:     /// </summary>
 125:     /// <param name="url">The URL.</param>
 126:     /// <param name="startIndex">The start index.</param>
 127:     /// <param name="itemsCount">The items count.</param>
 128:     /// <returns></returns>
 129:     private IEnumerable<Chapter> GetChapters(string url, int startIndex, int itemsCount)
 130:     {
 131:  
 132:  
 133:         //Return the range of chapters for a specified book
 134:         if (doc != null)
 135:         {
 136:  
 137:  
 138:             var chapters = (from d in doc.Descendants("book")
 139:                             where
 140:                                 (d.Attribute("Url").Value.Equals(url) && d.Descendants("chapter") != null &&
 141:                                  d.Descendants("chapter").Count() > 0)
 142:                             select GetChapters(d).ToList());
 143:  
 144:             if (chapters.Count() > 0 && chapters.First().Count > 0)
 145:             {
 146:                 List<Chapter> lst = chapters.First();
 147:  
 148:                 List<Chapter> result = new List<Chapter>();
 149:  
 150:                 for (int i = startIndex; i < startIndex + itemsCount; i++)
 151:                 {
 152:                     try
 153:                     {
 154:                         Chapter ch = lst[i];
 155:                         result.Add(ch);
 156:                     }
 157:                     catch (Exception)
 158:                     {
 159:                         continue;
 160:                     }
 161:                 }
 162:  
 163:                 return result;
 164:                 //return lst;
 165:                 //itemsCount = Math.Min(lst.Count - 1 - startIndex, itemsCount);
 166:                 //itemsCount = Math.Min(lst.Count - startIndex, itemsCount);
 167:                 //var x1 = new Chapter[itemsCount];
 168:  
 169:                 //try
 170:                 //{
 171:                 //    lst.CopyTo(startIndex, x1, 0, itemsCount);
 172:  
 173:                 //    //return lst;
 174:  
 175:                 //    return x1;
 176:                 //}
 177:                 //catch (Exception)
 178:                 //{
 179:                 //    return null;
 180:                 //}
 181:  
 182:             }
 183:  
 184:  
 185:         }
 186:  
 187:         return null;
 188:     }
 189:  
 190:     /// <summary>
 191:     /// Gets the chapters.
 192:     /// </summary>
 193:     /// <param name="parent">The parent.</param>
 194:     /// <returns></returns>
 195:     private static IEnumerable<Chapter> GetChapters(XElement parent)
 196:     {
 197:         return (from d in parent.Descendants("chapter")
 198:                 select new Chapter
 199:                 {
 200:                     Title = d.Attribute("Title").Value
 201:                 }).ToList<Chapter>();
 202:     }
 203:  
 204:     #endregion //GetChapters
 205:  
 206:     #region GetBookDataSource
 207:     /// <summary>
 208:     /// Gets the book data source.
 209:     /// </summary>
 210:     /// <returns></returns>
 211:     [OperationContract]
 212:     public IEnumerable<Book> GetBookDataSource()
 213:     {
 214:  
 215:         return GetBooks();
 216:  
 217:     }
 218:  
 219:     /// <summary>
 220:     /// Gets the book data source.
 221:     /// </summary>
 222:     /// <param name="startIndex">The start index.</param>
 223:     /// <param name="itemsCount">The items count.</param>
 224:     /// <returns></returns>
 225:     [OperationContract(Name = "GetRangeBookDataSource")]
 226:     public IEnumerable<Book> GetBookDataSource(int startIndex, int itemsCount)
 227:     {
 228:         return GetBooks(startIndex, itemsCount);
 229:  
 230:     }
 231:  
 232:     #endregion //GetBookDataSource
 233:  
 234:     #region GetBookChapters
 235:     /// <summary>
 236:     /// Gets the book data source.
 237:     /// </summary>
 238:     /// <returns></returns>
 239:     [OperationContract]
 240:     public IEnumerable<Chapter> GetBookChapters(string url)
 241:     {
 242:         return GetChapters(url);
 243:     }
 244:  
 245:     /// <summary>
 246:     /// Gets the book chapters.
 247:     /// </summary>
 248:     /// <param name="url">The URL.</param>
 249:     /// <param name="startIndex">The start index.</param>
 250:     /// <param name="itemsCount">The items count.</param>
 251:     /// <returns></returns>
 252:     [OperationContract(Name = "GetRangeBookChapters")]
 253:     public IEnumerable<Chapter> GetBookChapters(string url, int startIndex, int itemsCount)
 254:     {
 255:         return GetChapters(url, startIndex, itemsCount);
 256:     }
 257:  
 258:     #endregion //GetBookChapters
 259:  
 260:     #endregion //Methods
 261: }
 262: #endregion //BookDataSourceService

 

Client implementation:

The client application is a Silverlight navigation application, that implements the Model-View-ViewModel design pattern (MVVM).   ViewModels uses  custom collections, that inherits VirtualCollection<T>. In the application there are two views: one with XamGrid and another with XamDataTree.

ViewModels  implementation:

Implementation is a very similar to the one used in the article “On Demand Data Loading in XamTree” 

In the BookChaptersData collection load size is a smaller – fixed to 5 items

BookChaptersData implementation

   1: #region BookChaptersData
   2: public class BookChaptersData : VirtualCollection<Chapter>
   3: {
   4:     #region Member Variables
   5:  
   6:     private int _loadSize = 5;
   7:     private int _startIndex;
   8:  
   9:     #endregion //Member Variables
  10:  
  11:     #region Constructors
  12:  
  13:     public BookChaptersData()
  14:     {
  15:         this.LoadSize = _loadSize;
  16:         this.AnticipatedCount = _itemsCount;
  17:         this.ItemDataRequested += new EventHandler<ItemDataRequestedEventArgs>(BookChaptersData_ItemDataRequested);
  18:     }
  19:  
  20:     #endregion //Constructors
  21:  
  22:     #region Properties
  23:  
  24:     #region Client
  25:     private BookDataSourceServiceClient _client;
  26:     public BookDataSourceServiceClient Client
  27:     {
  28:         get
  29:         {
  30:             if (this._client == null)
  31:             {
  32:                 this._client = new BookDataSourceServiceClient();
  33:             }
  34:             return this._client;
  35:         }
  36:         set
  37:         {
  38:             this._client = value;
  39:             this.OnPropertyChanged("Client");
  40:         }
  41:     }
  42:     #endregion //Client
  43:  
  44:     #region ChapterBook
  45:     /// <summary>
  46:     /// local variable _ChapterBook
  47:     /// </summary>
  48:     private BookViewModel _chapterBook;
  49:  
  50:     /// <summary>
  51:     /// Identifies the ChapterBook property.
  52:     /// </summary>        
  53:     public BookViewModel ChapterBook
  54:     {
  55:         get { return _chapterBook; }
  56:         set
  57:         {
  58:             _chapterBook = value;
  59:             OnPropertyChanged("ChapterBook");
  60:         }
  61:     }
  62:     #endregion  //ChapterBook
  63:  
  64:     #region ItemsCount
  65:     /// <summary>
  66:     /// local variable _ItemsCount
  67:     /// </summary>
  68:     private int _itemsCount = 5;
  69:  
  70:     /// <summary>
  71:     /// Identifies the ItemsCount property.
  72:     /// </summary>        
  73:     public int ItemsCount
  74:     {
  75:         get { return _itemsCount; }
  76:         set
  77:         {
  78:             _itemsCount = value;
  79:             this.AnticipatedCount = _itemsCount;
  80:             OnPropertyChanged("ItemsCount");
  81:         }
  82:     }
  83:     #endregion  //ItemsCount
  84:  
  85:     #endregion //Properties
  86:  
  87:     #region EventHandlers
  88:  
  89:     #region BookChaptersData_ItemDataRequested
  90:     void BookChaptersData_ItemDataRequested(object sender, ItemDataRequestedEventArgs e)
  91:     {
  92:         if (this.ChapterBook == null)
  93:         {
  94:             return;
  95:         }
  96:  
  97:         this._startIndex = e.StartIndex;
  98:  
  99:         this._client.GetRangeBookChaptersAsync(this.ChapterBook.Url, e.StartIndex, e.ItemsCount);
 100:         if (this._client != null)
 101:         {
 102:             this._client.GetRangeBookChaptersCompleted -= ClientGetRangeBookChaptersCompleted;
 103:             this._client.GetRangeBookChaptersCompleted += new EventHandler<GetRangeBookChaptersCompletedEventArgs>(ClientGetRangeBookChaptersCompleted);
 104:             
 105:         }
 106:  
 107:     }
 108:     #endregion //BookChaptersData_ItemDataRequested
 109:  
 110:     #region ClientGetRangeBookChaptersCompleted
 111:     void ClientGetRangeBookChaptersCompleted(object sender, GetRangeBookChaptersCompletedEventArgs e)
 112:     {
 113:         if (e.Result != null)
 114:         {
 115:  
 116:             this.LoadItems(this._startIndex, e.Result);
 117:  
 118:         }
 119:     }
 120:     #endregion //ClientGetRangeBookChaptersCompleted
 121:  
 122:     #endregion //EventHandlers
 123: }
 124: #endregion //BookChaptersData

In some cases when the client application needs to receive quicker data (like when expand a XamDataTreeNode with many child nodes) we could force receiving the whole data moving to the last page(last part of data) in the collection. In the BookViewModel  there is added a method GetBookChapters that receives all additional data using a VirtualCollection method MoveToLastPage().

BookViewModel implementation:

   1: #region BookViewModel
   2: public class BookViewModel : Book
   3: {
   4:     #region Constructors
   5:  
   6:     public BookViewModel()
   7:     {
   8:     }
   9:  
  10:     public BookViewModel(Book book)
  11:     {
  12:         this.Author = book.Author;
  13:         this.Title = book.Title;
  14:         this.Url = book.Url;
  15:         this.ReleaseDate = book.ReleaseDate;
  16:         this.UnitPrice = book.UnitPrice;
  17:         this.Chapters = book.Chapters;
  18:         this.ChaptersCount = book.ChaptersCount;
  19:     }
  20:     #endregion //Constructors
  21:  
  22:     #region Properties
  23:  
  24:     #region Client
  25:     private BookDataSourceServiceClient _client;
  26:     public BookDataSourceServiceClient Client
  27:     {
  28:         get
  29:         {
  30:             if (this._client == null)
  31:             {
  32:                 this._client = new BookDataSourceServiceClient();
  33:             }
  34:             return this._client;
  35:         }
  36:         set
  37:         {
  38:             this._client = value;
  39:             this.RaisePropertyChanged("Client");
  40:         }
  41:     }
  42:  
  43:     #endregion //Client
  44:  
  45:  
  46:     #region BookChapters
  47:     /// <summary>
  48:     /// local variable _bookChapters
  49:     /// </summary>
  50:     private BookChaptersData _bookChapters;
  51:  
  52:     /// <summary>
  53:     /// Identifies the Chapters property.
  54:     /// </summary>        
  55:     public BookChaptersData BookChapters
  56:     {
  57:         get
  58:         {
  59:             if (_bookChapters == null)
  60:             {
  61:                 this._bookChapters = new BookChaptersData { Client = this.Client, ItemsCount = this.ChaptersCount, ChapterBook = this };
  62:                 this.RaisePropertyChanged("BookChapters");
  63:             }
  64:             return _bookChapters;
  65:         }
  66:         set
  67:         {
  68:             _bookChapters = value;
  69:             this.RaisePropertyChanged("BookChapters");
  70:         }
  71:     }
  72:  
  73:     #endregion  //BookChapters
  74:  
  75:     #endregion //Properties
  76:  
  77:     #region Methods
  78:  
  79:     #region GetBookChapters
  80:     public void GetBookChapters(int size)
  81:     {
  82:         if (this.BookChapters != null)
  83:         {
  84:             this.BookChapters.LoadSize = size;
  85:             this.BookChapters.MoveToLastPage();
  86:             this.RaisePropertyChanged("BookChapters");
  87:         }
  88:     }
  89:     #endregion //GetBookChapters
  90:  
  91:     #endregion //Methods
  92:  
  93: }
  94: #endregion //BookViewModel

 

View model are added as static resources on the application level. To see difference for both XamDataTree and XamGrid components in the application there are used two different instances of the  BookDataVcViewModel (BookDataVcViewModel  is a ViewModel, used as DataContext for views).

   1: <Application   
   2:   x:Class="XamGridLazyLoadingDemoApp.App"
   3:   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   4:   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   5:   xmlns:vm="clr-namespace:XamGridLazyLoadingDemoApp.ViewModels">
   6:  
   7:   <Application.Resources>
   8:     <ResourceDictionary>
   9:       <ResourceDictionary.MergedDictionaries>
  10:         <ResourceDictionary Source="Assets/Styles.xaml"/>
  11:       </ResourceDictionary.MergedDictionaries>
  12:     </ResourceDictionary>
  13:         <vm:BookDataViewModel x:Key="BookDataViewModel" />
  14:         <vm:BookDataVcViewModel x:Key="BookDataViewModelVC" />
  15:         <vm:BookDataVcViewModel x:Key="BookDataViewModelVC2" />
  16:     </Application.Resources>
  17:  
  18: </Application>

 

Views implementation:

XamGridVcLazyLoadingView implementation

Cerate a page, named XamGridVcLazyLoadingView with a XamGrid instance inside it:

   1: <Grid x:Name="LayoutRoot" DataContext="{StaticResource BookDataViewModelVC}" >
   2:     <Grid.RowDefinitions>
   3:         <RowDefinition Height="300" />
   4:         <RowDefinition/>
   5:     </Grid.RowDefinitions>
   6:     <ig:XamGrid x:Name="TestXamWebGrid"  AutoGenerateColumns="False" ItemsSource="{Binding Books}" SelectedRowsCollectionChanged="TestXamWebGrid_SelectedRowsCollectionChanged">
   7:         <ig:XamGrid.ExpansionIndicatorSettings>
   8:             <ig:ExpansionIndicatorSettings Visibility="Visible"/>
   9:         </ig:XamGrid.ExpansionIndicatorSettings>
  10:         <ig:XamGrid.SelectionSettings>
  11:             <ig:SelectionSettings  CellClickAction="SelectRow"
  12:             CellSelection="None" ColumnSelection="None"
  13:             RowSelection="Single" />
  14:         </ig:XamGrid.SelectionSettings>
  15:         <ig:XamGrid.RowSelectorSettings>
  16:             <ig:RowSelectorSettings Visibility="Visible" EnableRowNumbering="True"/>
  17:         </ig:XamGrid.RowSelectorSettings>
  18:         <ig:XamGrid.Columns>
  19:             <ig:TextColumn Key="Title" Width="200" HeaderText="Title:"/>
  20:             <ig:TextColumn Key="Author" Width="200" HeaderText="Author:"/>
  21:             <ig:TextColumn Key="UnitPrice" HeaderText="Unit Price:"/>
  22:             <ig:TextColumn Key="ChaptersCount" Width="70" HeaderText="Chapters Count:"/>
  23:             <ig:HyperlinkColumn Key="Url" Width="300" HeaderText="Url:"/>               
  24:             <ig:ColumnLayout Key="BookChapters">
  25:                 <ig:ColumnLayout.Columns>
  26:                     <ig:TextColumn Key="Title" HeaderText="Chapter Title:"/>
  27:                 </ig:ColumnLayout.Columns>                        
  28:             </ig:ColumnLayout>
  29:         </ig:XamGrid.Columns>
  30:         
  31:     </ig:XamGrid>
  32:     <Grid  Grid.Row="1" Visibility="Collapsed"
  33:               HorizontalAlignment="Stretch" Margin="0,10,0,0" Name="bookGrid" VerticalAlignment="Top">
  34:         <Grid.ColumnDefinitions>
  35:             <ColumnDefinition Width="Auto" />
  36:             <ColumnDefinition Width="Auto" />
  37:         </Grid.ColumnDefinitions>
  38:         <Grid.RowDefinitions>
  39:             <RowDefinition Height="Auto" />
  40:             <RowDefinition Height="Auto" />
  41:             <RowDefinition Height="Auto" />
  42:             <RowDefinition Height="Auto" />
  43:             <RowDefinition Height="Auto" />
  44:         </Grid.RowDefinitions>
  45:         <sdk:Label Content="Author:" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  46:         <TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="authorTextBox" Text="{Binding Path=Author, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
  47:         <sdk:Label Content="Release Date:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  48:         <TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="releaseDateTextBox" Text="{Binding Path=ReleaseDate, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
  49:         <sdk:Label Content="Title:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  50:         <TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="3" Name="titleTextBox" TextWrapping="Wrap" Text="{Binding Path=Title, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center"  MinWidth="120" />
  51:         <sdk:Label Content="Unit Price:" Grid.Column="0" Grid.Row="3" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  52:         <TextBox Grid.Column="1" Grid.Row="3" Height="23" HorizontalAlignment="Left" Margin="3" Name="unitPriceTextBox" Text="{Binding Path=UnitPrice, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
  53:         <sdk:Label Content="Url:" Grid.Column="0" Grid.Row="4" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  54:         <TextBox Grid.Column="1" Grid.Row="4" Height="23" HorizontalAlignment="Left" Margin="3" Name="urlTextBox" Text="{Binding Path=Url, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
  55:     </Grid>
  56: </Grid>

Column layouts are used to display only part of the properties from the hierarchical data.

   1: public partial class XamGridVcLazyLoadingView : Page
   2: {
   3:  
   4:     #region Constructors
   5:     public XamGridVcLazyLoadingView()
   6:     {
   7:         InitializeComponent();
   8:     }
   9:     #endregion //Constructors
  10:  
  11:     #region Methods
  12:  
  13:     #region OnNavigatedTo
  14:     // Executes when the user navigates to this page.
  15:     protected override void OnNavigatedTo(NavigationEventArgs e)
  16:     {
  17:     }
  18:     #endregion //OnNavigatedTo 
  19:  
  20:     #endregion //Methods
  21:  
  22:     #region EventHandlers
  23:  
  24:     #region TestXamWebGrid_SelectedRowsCollectionChanged
  25:     private void TestXamWebGrid_SelectedRowsCollectionChanged(object sender, Infragistics.Controls.Grids.SelectionCollectionChangedEventArgs<Infragistics.Controls.Grids.SelectedRowsCollection> e)
  26:     {
  27:  
  28:         if (e.NewSelectedItems != null && e.NewSelectedItems.Count > 0)
  29:         {
  30:             Row row = e.NewSelectedItems[0];
  31:             var book = row.Data as BookViewModel;
  32:             if (book != null)
  33:             {
  34:                 if (bookGrid.Visibility == System.Windows.Visibility.Collapsed)
  35:                 {
  36:                     bookGrid.Visibility = System.Windows.Visibility.Visible;
  37:                 }
  38:                 bookGrid.DataContext = book;
  39:                 book.GetBookChapters(book.ChaptersCount);
  40:             }
  41:         }
  42:  
  43:     }
  44:     #endregion //TestXamWebGrid_SelectedRowsCollectionChanged
  45:  
  46:     #endregion //EventHandlers
  47: }

 

First time when data is loaded there are loaded only first 5 chapters from each book where are chapters available. All other chapters are loaded part by part when a parent row is expanded. Expansion indicators are visible only for the rows, representing books with available chapters.

XamDataTreeVcLazyLoadingView implementation

Cerate a page, named XamDataTreeVcLazyLoadingView with a XamDataTree instance inside it:

   1: <Grid x:Name="LayoutRoot" DataContext="{StaticResource BookDataViewModelVC2}">
   2:     <Grid.ColumnDefinitions>
   3:         <ColumnDefinition Width="380"/>
   4:         <ColumnDefinition/>
   5:     </Grid.ColumnDefinitions>
   6:     <ig:XamDataTree x:Name="BookDataTree" NodeExpansionChanged="BookDataTree_NodeExpansionChanged" ItemsSource="{Binding Books}" SelectedNodesCollectionChanged="BookDataTree_SelectedNodesCollectionChanged" >
   7:         <ig:XamDataTree.SelectionSettings>
   8:             <ig:TreeSelectionSettings NodeSelection="Single"/>
   9:         </ig:XamDataTree.SelectionSettings>
  10:         <ig:XamDataTree.GlobalNodeLayouts>
  11:             <ig:NodeLayout Key="BookChapters" TargetTypeName="BookViewModel" DisplayMemberPath="Title"/>
  12:         </ig:XamDataTree.GlobalNodeLayouts>
  13:     </ig:XamDataTree>
  14:     <Grid Grid.Column="1">
  15:         <Grid.RowDefinitions>
  16:             <RowDefinition Height="60"/>
  17:             <RowDefinition/>
  18:         </Grid.RowDefinitions>
  19:         <StackPanel Orientation="Vertical">
  20:             <TextBlock x:Name="TxtTitleBook" >
  21:                 <Run Text="XamDataTree and VirtualCollection"/>
  22:                 <LineBreak/>
  23:                 <Run Text="lazy Loading Sample:"/>
  24:             </TextBlock>
  25:             <TextBlock x:Name="TxtSelectedBook" Text="Select Book:"/>
  26:         </StackPanel>
  27:  
  28:         <Grid Grid.Row="1" Visibility="Collapsed"
  29:               HorizontalAlignment="Stretch" Margin="0,10,0,0" Name="bookGrid" VerticalAlignment="Top">
  30:             <Grid.ColumnDefinitions>
  31:                 <ColumnDefinition Width="Auto" />
  32:                 <ColumnDefinition Width="Auto" />
  33:             </Grid.ColumnDefinitions>
  34:             <Grid.RowDefinitions>
  35:                 <RowDefinition Height="Auto" />
  36:                 <RowDefinition Height="Auto" />
  37:                 <RowDefinition Height="Auto" />
  38:                 <RowDefinition Height="Auto" />
  39:                 <RowDefinition Height="Auto" />
  40:             </Grid.RowDefinitions>
  41:             <sdk:Label Content="Author:" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  42:             <TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="authorTextBox" Text="{Binding Path=Author, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
  43:             <sdk:Label Content="Release Date:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  44:             <TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="releaseDateTextBox" Text="{Binding Path=ReleaseDate, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
  45:             <sdk:Label Content="Title:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  46:             <TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="3" Name="titleTextBox" TextWrapping="Wrap" Text="{Binding Path=Title, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center"  MinWidth="120" />
  47:             <sdk:Label Content="Unit Price:" Grid.Column="0" Grid.Row="3" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  48:             <TextBox Grid.Column="1" Grid.Row="3" Height="23" HorizontalAlignment="Left" Margin="3" Name="unitPriceTextBox" Text="{Binding Path=UnitPrice, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
  49:             <sdk:Label Content="Url:" Grid.Column="0" Grid.Row="4" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
  50:             <TextBox Grid.Column="1" Grid.Row="4" Height="23" HorizontalAlignment="Left" Margin="3" Name="urlTextBox" Text="{Binding Path=Url, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
  51:         </Grid>
  52:     </Grid>
  53: </Grid>

 

When some XamDataTreeNode instance, representing a book was expanded, all additional data for the book chapters is loaded from the server, calling GetBookChapters method:

   1: #region XamDataTreeVcLazyLoadingView
   2: public partial class XamDataTreeVcLazyLoadingView : Page
   3: {
   4:     #region Constructors
   5:     public XamDataTreeVcLazyLoadingView()
   6:     {
   7:         InitializeComponent();
   8:     }
   9:     #endregion //Constructors
  10:  
  11:     #region Methods
  12:     #region OnNavigatedTo
  13:     /// <summary>
  14:     /// Called when a page becomes the active page in a frame.
  15:     /// </summary>
  16:     /// <param name="e">An object that contains the event data.</param>
  17:     protected override void OnNavigatedTo(NavigationEventArgs e)
  18:     {
  19:     }
  20:     #endregion //OnNavigatedTo 
  21:     #endregion //Methods
  22:  
  23:     #region EventHandlers
  24:     #region BookDataTree_SelectedNodesCollectionChanged
  25:     private void BookDataTree_SelectedNodesCollectionChanged(object sender, Infragistics.Controls.Menus.NodeSelectionEventArgs e)
  26:     {
  27:  
  28:         if (e.CurrentSelectedNodes != null && e.CurrentSelectedNodes.Count > 0)
  29:         {
  30:             XamDataTreeNode node = e.CurrentSelectedNodes[0];
  31:  
  32:             var book = node.Data as BookViewModel;
  33:             if (book != null)
  34:             {
  35:                 if (bookGrid.Visibility == System.Windows.Visibility.Collapsed)
  36:                 {
  37:                     bookGrid.Visibility = System.Windows.Visibility.Visible;
  38:                 }
  39:                 bookGrid.DataContext = book;
  40:             }
  41:         }
  42:  
  43:     }
  44:     #endregion //BookDataTree_SelectedNodesCollectionChanged
  45:  
  46:     #region BookDataTree_NodeExpansionChanged
  47:     private void BookDataTree_NodeExpansionChanged(object sender, NodeExpansionChangedEventArgs e)
  48:     {
  49:         XamDataTreeNode node = e.Node;
  50:         if (node != null && node.IsExpanded)
  51:         {
  52:             var book = node.Data as BookViewModel;
  53:             if (book != null)
  54:             {
  55:                 book.BookChapters.LoadSize = book.ChaptersCount;
  56:                 book.GetBookChapters(book.ChaptersCount);
  57:             }
  58:         }
  59:  
  60:     }
  61:     #endregion //BookDataTree_NodeExpansionChanged 
  62:     #endregion //EventHandlers
  63:  
  64: }
  65: #endregion //XamDataTreeVcLazyLoadingView

 

Run the application:

The home page is a XamGridVcLazyLoadingView.
Data for the visible rows is loaded. Only first 5 chapters for books where is available data for book chapters are loaded. This is enough to recognize where are child records via expansion indicators.

Select a row. Data for the selected book is visible below the XamGrid.

Expand the selected row. Only data for the visible rows will be loaded.

Scroll down to see other chapters. Data is loaded part by part.

Select a page  “XamDataTree with VirtualCollection” ( XamDataTreeVcLazyLoadingView ).

Select some node - data for the selected book is visible right the XamDataTree.

Expand the selected node - all additional data for the book chapters is loaded.

Sample code could be downloaded here: