protected internal override void OnQueryItems(VirtualPage page, AsyncQueryInfo queryInfo)
        {
            base.OnQueryItems(page, queryInfo);

            DataGridVirtualizingQueryableCollectionViewGroup collectionViewGroup =
                this.GetLinkedCollectionViewGroup(page.ParentVirtualList) as DataGridVirtualizingQueryableCollectionViewGroup;

            IQueryable queryableToUse;

            int virtualItemCount = collectionViewGroup.VirtualItemCount;

            bool queryableIsReversed;

            if ((!m_supportsPrimaryKeyOptimizations) || (queryInfo.StartIndex < (virtualItemCount / 2)))
            {
                queryableIsReversed = false;
                queryableToUse      = collectionViewGroup.Queryable.Slice(queryInfo.StartIndex, queryInfo.RequestedItemCount);
            }
            else
            {
                queryableIsReversed = true;

                int reversedStartIndex = virtualItemCount - (queryInfo.StartIndex + queryInfo.RequestedItemCount);

                queryableToUse = collectionViewGroup.ReversedQueryable.Slice(reversedStartIndex, queryInfo.RequestedItemCount);
            }

            System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.AsyncGatherItems), new object[] { queryInfo, queryableToUse, queryableIsReversed });
        }
        protected internal override void OnQueryItemsCompleted(VirtualPage page, AsyncQueryInfo queryInfo, object[] fetchedItems)
        {
            base.OnQueryItemsCompleted(page, queryInfo, fetchedItems);

            Debug.Assert(m_asyncQueryInfosInProgress.Contains(queryInfo));
            m_asyncQueryInfosInProgress.Remove(queryInfo);

            this.UpdateConnectionState();
        }
Beispiel #3
0
        private void AsyncQueryInfo_BeginQueryItems(AsyncQueryInfo queryInfo)
        {
            if (this.IsDisposed)
            {
                return;
            }

            Debug.Assert((this.ParentVirtualList != null) || (this.ParentVirtualList.PagingManager != null));

            this.ParentVirtualList.PagingManager.OnQueryItems(this, queryInfo);
        }
Beispiel #4
0
        private void AsyncQueryInfo_BuiltInAbort(AsyncQueryInfo queryInfo)
        {
            if (this.IsDisposed)
            {
                return;
            }

            Debug.Assert((this.ParentVirtualList != null) || (this.ParentVirtualList.PagingManager != null));

            this.ParentVirtualList.PagingManager.OnBuiltInAbort(this, queryInfo);
            this.IsAborting = false;
        }
        protected internal override void OnQueryItemsCompleted(VirtualPage page, AsyncQueryInfo queryInfo, object[] fetchedItems)
        {
            DataGridVirtualizingCollectionView collectionView = this.CollectionView as DataGridVirtualizingCollectionView;

            // The VirtualPageManager was Disposed
            if (collectionView == null)
            {
                return;
            }

            using (collectionView.DeferRefresh())
            {
                base.OnQueryItemsCompleted(page, queryInfo, fetchedItems);
            }
        }
        protected internal override void OnAbortQueryItems(VirtualPage page, AsyncQueryInfo queryInfo)
        {
            base.OnAbortQueryItems(page, queryInfo);

            // It is possible that the queryInfo was removed previously
            m_asyncQueryInfosInProgress.Remove(queryInfo);

            // In case the page query was aborted when
            // VirtualPageManager.CleanUpUnused is called
            if (page.RemoveAfterOperation)
            {
                this.RemovePage(page);
            }

            this.UpdateConnectionState();
        }
        internal void OnQueryItems(AsyncQueryInfo asyncQueryInfo, DataGridVirtualizingCollectionViewGroup collectionViewGroup)
        {
            QueryItemsEventArgs e = new QueryItemsEventArgs(this, collectionViewGroup, asyncQueryInfo);

            if (this.QueryItems != null)
            {
                this.QueryItems(this, e);
            }

            DataGridVirtualizingCollectionViewSource source = this.ParentCollectionViewSourceBase as DataGridVirtualizingCollectionViewSource;

            if (source != null)
            {
                source.OnQueryItems(e);
            }
        }
Beispiel #8
0
        private void AsyncQueryInfo_EndQueryItems(AsyncQueryInfo queryInfo, object[] fetchedItems)
        {
            if (this.IsDisposed)
            {
                return;
            }

            Debug.Assert((this.ParentVirtualList != null) || (this.ParentVirtualList.PagingManager != null));
            Debug.Assert(!this.IsAborting);
            this.ParentVirtualList.PagingManager.OnQueryItemsCompleted(this, queryInfo, fetchedItems);

            if (this.ParentVirtualList.IsRestarting)
            {
                this.Restart();
            }
        }
Beispiel #9
0
        private void AsyncQueryInfo_QueryErrorChanged(AsyncQueryInfo queryInfo)
        {
            if (this.IsDisposed)
            {
                return;
            }

            Debug.Assert((this.ParentVirtualList != null) || (this.ParentVirtualList.PagingManager != null));

            this.ParentVirtualList.PagingManager.OnQueryErrorChanged(this, queryInfo);

            if (this.ParentVirtualList.IsRestarting)
            {
                this.Restart();
            }
        }
        protected internal override void OnAbortQueryItems(VirtualPage page, AsyncQueryInfo queryInfo)
        {
            DataGridVirtualizingCollectionView collectionView = this.CollectionView as DataGridVirtualizingCollectionView;

            // The VirtualPageManager was Disposed
            if (collectionView == null)
            {
                return;
            }

            DataGridVirtualizingCollectionViewGroup collectionViewGroup = this.GetLinkedCollectionViewGroup(page.ParentVirtualList) as DataGridVirtualizingCollectionViewGroup;

            collectionView.OnAbortQueryItems(queryInfo, collectionViewGroup);

            base.OnAbortQueryItems(page, queryInfo);
        }
        protected internal override void OnBuiltInAbort(VirtualPage page, AsyncQueryInfo queryInfo)
        {
            // When a built-in abort occurs, we ensure to remove
            // any AsyncQueryInfo from references since the ConnectionState
            // use this array to update its actual state
            m_asyncQueryInfosInProgress.Remove(queryInfo);

            // In case the page query was aborted when
            // VirtualPageManager.CleanUpUnused is called
            if (page.RemoveAfterOperation)
            {
                this.RemovePage(page);
            }

            this.UpdateConnectionState();
        }
Beispiel #12
0
        internal QueryItemsEventArgs(
            DataGridVirtualizingCollectionView collectionView,
            DataGridVirtualizingCollectionViewGroup collectionViewGroup,
            AsyncQueryInfo asyncQueryInfo)
        {
            m_dataGridVirtualizingCollectionView = collectionView;

            // The collectionViewGroup can be null when we abort
            // a QueryItems for the old RootGroup when
            // DataGridVirtualizingCollectionViewBase.ForceRefresh
            // is called
            m_readonlyGroupPath = (collectionViewGroup != null)
        ? collectionViewGroup.GroupPath.AsReadOnly()
        : new ReadOnlyCollection <DataGridGroupInfo>(new List <DataGridGroupInfo>());

            m_asyncQueryInfo = asyncQueryInfo;
        }
Beispiel #13
0
        internal void QueueQueryData(Dispatcher dispatcher)
        {
            Debug.Assert(!this.IsDisposed);

            Debug.Assert(m_asyncQueryInfo == null);

            m_asyncQueryInfo = new AsyncQueryInfo(
                dispatcher,
                new Action <AsyncQueryInfo>(this.AsyncQueryInfo_BeginQueryItems),
                new Action <AsyncQueryInfo>(this.AsyncQueryInfo_AbortQueryItems),
                new Action <AsyncQueryInfo, object[]>(this.AsyncQueryInfo_EndQueryItems),
                new Action <AsyncQueryInfo>(this.AsyncQueryInfo_QueryErrorChanged),
                new Action <AsyncQueryInfo>(this.AsyncQueryInfo_BuiltInAbort),
                m_startDataIndex,
                this.Count);

            m_asyncQueryInfo.QueueQuery();
        }
Beispiel #14
0
        public void Dispose()
        {
            Debug.Assert(!this.IsDisposed);

            Debug.Assert((m_asyncCommitInfoList != null) && (m_asyncCommitInfoList.Count == 0), "Some async commit are not completed while disposing VirtualPage");

            if (m_asyncQueryInfo != null)
            {
                // We must dispose the AsyncQueryInfo to be sure
                // it does not root this VirtualPage instance
                m_asyncQueryInfo.Dispose();
                m_asyncQueryInfo = null;
            }

            this.Clear();
            m_parentVirtualList = null;

            this.IsDisposed = true;
        }
Beispiel #15
0
        private void AsyncQueryInfo_AbortQueryItems(AsyncQueryInfo queryInfo)
        {
            if (this.IsDisposed)
            {
                return;
            }

            Debug.Assert((this.ParentVirtualList != null) || (this.ParentVirtualList.PagingManager != null));

            this.ParentVirtualList.PagingManager.OnAbortQueryItems(this, queryInfo);

            this.IsAborting = false;

            // If the page was removed, it was also disposed.
            // This case means the page was not restarting
            if (!this.RemoveAfterOperation && this.ParentVirtualList.IsRestarting)
            {
                this.Restart();
            }
        }
        protected internal override void OnQueryErrorChanged(VirtualPage page, AsyncQueryInfo queryInfo)
        {
            base.OnQueryErrorChanged(page, queryInfo);

            // It is possible that m_asyncQueryInfosInProgress does not contain the queryInfo when
            // the query was aborted but the user did not stop the query and later on set the queryInfo error
            // event if the queryInfo ShouldAbort is set to True.
            Debug.Assert((m_asyncQueryInfosInProgress.Contains(queryInfo)) || (queryInfo.ShouldAbort));

            object error = queryInfo.Error;

            if (error == null)
            {
                // Even if the queryInfo's ShouldAbort property is set to True, clean-up the error.
                Debug.Assert((m_asyncQueryInfosInError != null) && (m_asyncQueryInfosInError.Contains(queryInfo)));

                m_asyncQueryInfosInError.Remove(queryInfo);

                if (m_asyncQueryInfosInError.Count == 0)
                {
                    m_asyncQueryInfosInError = null;
                }
            }
            else if (!queryInfo.ShouldAbort)
            {
                // Only add errors if the queryInfo's ShouldAbort property is set to False.
                if (m_asyncQueryInfosInError == null)
                {
                    m_asyncQueryInfosInError = new LinkedList <AsyncQueryInfo>();
                }

                if (m_asyncQueryInfosInError.Contains(queryInfo))
                {
                    m_asyncQueryInfosInError.Remove(queryInfo);
                }

                m_asyncQueryInfosInError.AddFirst(queryInfo);
            }

            this.UpdateConnectionState();
        }
Beispiel #17
0
        internal void EndQueryItems(AsyncQueryInfo asyncQueryInfo, object[] items)
        {
            Debug.Assert(!this.IsDisposed);

            // This can occur when the user notify us that the QueryData is completed for an AsyncQueryInfo.StartIndex that refers to a Page which does exists
            // but that was removed, then re-created thus creating another asyncQueryInfo and queuing another QueryData.
            // The only way to get rid of this situation would be to keep a ref to the queued asyncQueryInfo even if we get rid of the page and re-link the same instance
            // to the newly created page.  This optimization could be done in a future version.  For now, let's return and the second asyncQueryInfo will take care of filling
            // the newly created page.
            if (m_asyncQueryInfo != asyncQueryInfo)
            {
                Debug.Assert(false);
                return;
            }

            if (this.IsFilled)
            {
                throw new InvalidOperationException("An attempt was made to fill a virtual page that is already filled.");
            }

            if (items == null)
            {
                throw new ArgumentNullException("items");
            }

            for (int i = 0; i < items.Length; i++)
            {
                VirtualizedItemInfo virtualizedItemInfo = this[i];

                Debug.Assert(virtualizedItemInfo.DataItem is EmptyDataItem);
                Debug.Assert(virtualizedItemInfo.Index == (m_startDataIndex + i));

                this[i].DataItem = items[i];
            }

            this.IsFilled = true;
            Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "Page Filled - " + this.ToString());
        }
        protected internal override void OnQueryItems(VirtualPage page, AsyncQueryInfo queryInfo)
        {
            // The VirtualPageManager is not connected to the CollectionView anymore,
            // do NOT query items since it will be done by the new VirtualPageManager
            // assigned to the same CollectionView
            if (!this.IsConnected)
            {
                return;
            }

            Debug.Assert(!m_asyncQueryInfosInProgress.Contains(queryInfo));
            m_asyncQueryInfosInProgress.Add(queryInfo);

            if (m_asyncQueryInfosInError != null)
            {
                LinkedListNode <AsyncQueryInfo> queryInfoInErrorNode = m_asyncQueryInfosInError.First;

                while (queryInfoInErrorNode != null)
                {
                    if (DataGridPageManagerBase.QueryInfoWeakComparer.Equals(queryInfo, queryInfoInErrorNode.Value))
                    {
                        m_asyncQueryInfosInError.Remove(queryInfoInErrorNode);
                        break;
                    }

                    queryInfoInErrorNode = queryInfoInErrorNode.Next;
                }

                if (m_asyncQueryInfosInError.Count == 0)
                {
                    m_asyncQueryInfosInError = null;
                }
            }

            this.UpdateConnectionState();
        }
Beispiel #19
0
        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));
            }
        }
 protected internal abstract void OnBuiltInAbort(VirtualPage virtualPage, AsyncQueryInfo queryInfo);
 protected internal abstract void OnQueryItems(VirtualPage page, AsyncQueryInfo queryInfo);
 protected internal virtual void OnAbortQueryItems(VirtualPage page, AsyncQueryInfo queryInfo)
 {
 }
        protected internal virtual void OnQueryItemsCompleted(VirtualPage page, AsyncQueryInfo queryInfo, object[] fetchedItems)
        {
            this.IncrementVersion();

            page.ParentVirtualList.FillEmptyPage(queryInfo, fetchedItems);
        }
 protected internal virtual void OnQueryErrorChanged(VirtualPage page, AsyncQueryInfo queryInfo)
 {
 }
        private void AsyncGatherItems(object workItem)
        {
            object[] parameters = ( object[] )workItem;

            AsyncQueryInfo queryInfo = parameters[0] as AsyncQueryInfo;

            if (queryInfo.ShouldAbort)
            {
                return;
            }

            IQueryable queryable          = ( IQueryable )parameters[1];
            int        requestedItemCount = queryInfo.RequestedItemCount;

            object[] items = new object[requestedItemCount];

            System.Collections.IEnumerator enumerator;

            lock ( m_syncRoot )
            {
                // We reverify here since a reset could have been issued while we were waiting on the lock statement.
                if ((queryInfo.ShouldAbort) || (!this.IsConnected) || (this.IsDisposed))
                {
                    return;
                }

                try
                {
                    Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "Beginning Provider Execute for page at start index: " + queryInfo.StartIndex.ToString());

                    enumerator = queryable.GetEnumerator();

                    Debug.WriteLineIf(VirtualPageManager.DebugDataVirtualization, "Ended Provider Execute for page at start index: " + queryInfo.StartIndex.ToString());

                    int i = 0;

                    while (enumerator.MoveNext() && (i < requestedItemCount))
                    {
                        object current = enumerator.Current;

                        if (current != null)
                        {
                            items[i] = enumerator.Current;
                            i++;
                        }
                    }
                }
                catch (Exception exception)
                {
                    // TimeOut exeception or other.
                    queryInfo.AbortQuery();
                    queryInfo.Error = exception.Message;
                    return;
                }
            }

            items = items.Where(item => item != null).ToArray();

            try
            {
                if (items.Count() != requestedItemCount)
                {
                    throw new InvalidOperationException("TODODOC : The number of non-null items return by the source must be equal to the provided item count");
                }
            }
            catch
            {
                //go silently here, in case the next sequance give a valid result.  At the same time, if it does not, the dev has information when debugging.
            }

            bool queryableWasReversed = ( bool )parameters[2];

            if (queryableWasReversed)
            {
                Array.Reverse(items);
            }

            queryInfo.EndQuery(items);
        }