public override string ToString() { StringBuilder builder = new StringBuilder(); ReadOnlyCollection <VirtualPage> virtualPages = m_tableOfContent.VirtualPages; int pageCount = virtualPages.Count; for (int i = 0; i < pageCount; i++) { VirtualPage page = virtualPages[i]; builder.Append(i.ToString() + ": Page " + page.ToString() + Environment.NewLine); } return(builder.ToString()); }
private VirtualPage CreateNewPage(int itemIndex) { Debug.Assert(!m_tableOfContent.ContainsPageForSourceIndex(itemIndex)); int pageStartIndex = this.GetPageStartingIndexForItemIndex(itemIndex); int pageSize = m_pagingManager.PageSize; int expectedItemCount = Math.Min(pageSize, (m_virtualCount - pageStartIndex)); expectedItemCount = Math.Max(0, expectedItemCount); VirtualPage page = VirtualPage.CreateEmptyPage(this, pageStartIndex, expectedItemCount); m_tableOfContent.AddPage(page); // If we have a pending commit page, this brandly new created page will get its query data queued when we are notified // of a commit completed and that we no longer have any pages awaiting commiting. if (!this.HasPagePendingCommit) { m_pagingManager.QueueQueryData(page); } Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "Creating VirtualItemPlaceHolder for page: " + page.ToString()); return(page); }
internal void FillEmptyPage(AsyncQueryInfo asyncQueryInfo, object[] fetchedItems) { // The VirtualList is disposed or part of a PagingManager // that will be disposed (only disconnected when dispose is required) if (!this.PagingManager.IsConnected) { return; } Debug.Assert(!this.IsDisposed); Debug.Assert(!asyncQueryInfo.IsDisposed); // We do not want to move the page we are about to fill to the front since it does not count as a legitimate user-acess. // It will get moved to the front when one of its item is accessed. VirtualPage page = null; page = this.GetPageOrDefaultForItemIndex(asyncQueryInfo.StartIndex, true); // Although extremely rare, this situation could occur if we are calling RemovePageNode and the QueryData Dispatcher Operation // which has been asyncronously invoked in CreateNewPage is raising the QueryData event at the exact moment when we // try to abort the dispatcher operation. This means that the customer will have queued an async request for data // for a page we no longer care about, and have already removed from the Table of Content and our LinkedList. // This should NOT occur if the user did not abort the request and called the AsyncQueryInfo EndQuery method since AsyncQueryInfo should // not have invoked the EndQueryAction if its ShouldAbort property was set to true. if (page == null) { return; } Debug.Assert(!page.IsFilled); Debug.Assert(this.GetPageStartingIndexForItemIndex(asyncQueryInfo.StartIndex) == asyncQueryInfo.StartIndex); Debug.Assert(fetchedItems.Length <= page.Count); if (fetchedItems.Length == page.Count) { object[] oldItems = page.ToItemArray(); m_tableOfContent.RemovePage(page); page.EndQueryItems(asyncQueryInfo, fetchedItems); m_tableOfContent.AddPage(page); Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "Replaced TOC items/index for page: " + page.ToString()); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Replace, fetchedItems, oldItems, asyncQueryInfo.StartIndex)); } else { // The expected count was not met. Maybe the user told us the source was bigger than it really is, or maybe there // were delete operations made on the source since the last restart. // // Let's refresh the CollectionView. // This will restart the VirtualItemBook and raise the CollectionView's OnCollectionChanged Reset notification. this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } }
internal void AddPage(VirtualPage page, PageInsertPosition insertPosition) { if (page == null) { throw new ArgumentNullException("page", "TODOOC: An internal error occured while paging data. Page cannot be null."); } // We call clean-up before the call to AddFirst since if we do // it afterward and the page is pending fill, we will remove it. this.CleanUpAndDisposeUnused(); if (insertPosition == PageInsertPosition.Front) { m_pageNodes.AddFirst(page); } else { m_pageNodes.AddLast(page); } Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "Added To " + ((insertPosition == PageInsertPosition.Front) ? "Front" : "Back") + ": Page " + page.ToString()); }
internal void MovePageToFront(VirtualPage page) { // The further from the front a page is, the longer it has been since it was requested. Debug.Assert(page != null); LinkedListNode <VirtualPage> firstNode = m_pageNodes.First; if (firstNode.Value != page) { LinkedListNode <VirtualPage> node = m_pageNodes.Find(page); m_pageNodes.Remove(node); m_pageNodes.AddFirst(node); Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "Moved To Front: Page " + page.ToString()); } }
internal void RemovePage(VirtualPage page) { if (page.IsDisposed) { return; } Debug.Assert(page != null); //Debug.Assert( !page.IsRestarting ); Debug.Assert(!page.IsDirty); // A filled page is being removed. Change the version. this.IncrementVersion(); // Update the table of content of the page's ParentVirtualList page.ParentVirtualList.TableOfContent.RemovePage(page); m_pageNodes.Remove(page); Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "Removed Page: " + page.ToString()); // Dispose the page since it will never be reused page.Dispose(); }
internal void QueueCommitData(VirtualPage page) { Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "QueueCommitData for page " + page.ToString()); Debug.Assert(m_managedLists.Contains(page.ParentVirtualList)); Debug.Assert(page.IsFilled); Debug.Assert(page.IsDirty); if (this.RestartingManager) { this.ShouldRefreshAfterRestart = true; } page.QueueCommitData(this.Dispatcher); }
protected internal override void OnCommitItemsCompleted(VirtualPage page, AsyncCommitInfo commitInfo) { Debug.Assert(m_asyncCommitInfosInProgress.Contains(commitInfo)); m_asyncCommitInfosInProgress.Remove(commitInfo); this.UpdateConnectionState(); base.OnCommitItemsCompleted(page, commitInfo); // In case the page query was aborted when // VirtualPageManager.CleanUpUnused is called if (page.RemoveAfterOperation) { this.RemovePage(page); } Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "OnCommitItemsCompleted for page " + page.ToString()); }
protected internal override void OnCommitItems(VirtualPage page, AsyncCommitInfo commitInfo) { base.OnCommitItems(page, commitInfo); Debug.Assert(!m_asyncCommitInfosInProgress.Contains(commitInfo)); m_asyncCommitInfosInProgress.Add(commitInfo); this.UpdateConnectionState(); Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "OnCommitItems for page " + page.ToString()); m_collectionView.Dispatcher.BeginInvoke( new Action <VirtualPage, AsyncCommitInfo>(this.RaiseCollectionViewOnCommitItems), DispatcherPriority.Background, page, commitInfo); }