/// <summary> /// Refreshes the work items in the document. /// </summary> /// <remarks> /// <para>Deletes work items that are no longer returned, adds work items that are now returned, and re-orders work items that have changed position in query results.</para> /// <para>This call will also update the rich text content controls which are not bound to the Custom XML Parts.</para> /// </remarks> /// <param name="refreshData">The data needed for a refresh.</param> /// <param name="bookmarkNamingFunction">A function to return the bookmark to use for the given work item, first parameter is query index, second is work item id.</param> /// <param name="cancellationToken">Used to cancel the refresh.</param> public void RefreshWorkItems(FormatterRefreshData refreshData, Func <int, int, string> bookmarkNamingFunction, CancellationToken cancellationToken) { if (refreshData == null) { throw new ArgumentNullException("refreshData"); } Debug.Assert(refreshData.QueryWorkItemsBefore.Count() == refreshData.QueryWorkItemsAfter.Count(), "Before and after data have different numbers of queries"); Debug.Assert(refreshData.QueryWorkItemsBefore.Count() == refreshData.Layouts.Count(), "Number of layouts does not match number of queries"); Debug.Assert(refreshData.QueryWorkItemsBefore.Count() == refreshData.QueryIsFlat.Count(), "Number of QueryIsFlat values does not match number of queries"); DateTime start = DateTime.Now; CustomXMLPart part = this.wordDocument.GetXmlPart(Constants.WorkItemNamespace); int n = refreshData.QueryWorkItemsBefore.Count(); QueryWorkItems[] queryWorkItemsBefore = refreshData.QueryWorkItemsBefore.ToArray(); QueryWorkItems[] queryWorkItemsAfter = refreshData.QueryWorkItemsAfter.ToArray(); bool[] queryIsFlat = refreshData.QueryIsFlat.ToArray(); LayoutInformation[] layouts = refreshData.Layouts.ToArray(); for (int queryIndex = 0; queryIndex < n; queryIndex++) { Func <int, string> queryBookmarkNamingFunction = (int id) => bookmarkNamingFunction(queryIndex, id); this.logger.Log(TraceEventType.Verbose, "Refreshing query {0}", queryIndex); // Compute the actual before work items that are still in the document. QueryWorkItems actualBeforeWorkItems = new QueryWorkItems(queryIndex, queryWorkItemsBefore[queryIndex].WorkItemIds.Where(id => this.FindBookmark(queryBookmarkNamingFunction(id)) != null).ToArray()); bool isManuallySorted = this.IsManuallySorted(queryWorkItemsBefore[queryIndex].WorkItemIds, queryBookmarkNamingFunction); if (!queryIsFlat[queryIndex] || (queryIsFlat[queryIndex] && !isManuallySorted)) { this.SortExistingWorkItems(actualBeforeWorkItems, queryWorkItemsAfter[queryIndex], queryBookmarkNamingFunction, cancellationToken); isManuallySorted = false; } IWorkItemLayout workItemLayout = new WorkItemLayout(layouts[queryIndex], this.teamProjectTemplate); this.AddNewWorkItems(actualBeforeWorkItems, queryWorkItemsAfter[queryIndex], workItemLayout, part, queryBookmarkNamingFunction, isManuallySorted, cancellationToken); } this.RefreshDeleteRemovedWorkItems(refreshData.QueryWorkItemsBefore.ToArray(), refreshData.QueryWorkItemsAfter.ToArray(), bookmarkNamingFunction, cancellationToken); this.RefreshRichTextContentControls(refreshData.WorkItemManager, cancellationToken); DateTime end = DateTime.Now; this.logger.Log(TraceEventType.Information, "Elapsed time to refresh was {0} seconds", (end - start).TotalSeconds); }
/// <summary> /// Refreshes the work items in the document. /// </summary> /// <remarks> /// This call will update the rich text content controls which are not bound to the Custom XML Parts. /// </remarks> /// <param name="cancellationToken">Used to cancel the save.</param> /// <returns>List of verification errors, empty if there were no errors.</returns> public IEnumerable <string> RefreshWorkItems(CancellationToken cancellationToken) { IEnumerable <string> ans; if (this.queryAndLayoutManager == null) { throw new InvalidOperationException(ModelResources.TeamProjectNotSet); } ans = this.verifier.VerifyDocument(this.queryWorkItems.ToArray(), Utilities.BookmarkNamingFunction, Utilities.BookmarkParsingFunction, Utilities.XpathParsingFunction); if (ans.Count() == 0) { this.workItemManager.Clear(); List <QueryWorkItems> afterQueryWorkItems = new List <QueryWorkItems>(); foreach (QueryAndLayoutInformation queryAndLayout in this.queryAndLayoutManager.FinalQueriesAndLayouts) { cancellationToken.ThrowIfCancellationRequested(); QueryDefinition finalQuery = queryAndLayout.Query; WorkItemTree workItems = this.teamProject.QueryRunner.QueryForWorkItems(finalQuery, cancellationToken); afterQueryWorkItems.Add(new QueryWorkItems(afterQueryWorkItems.Count, workItems.DepthFirstNodes().ToArray())); this.workItemManager.AddRange(workItems.DepthFirstNodes().Select(node => node.WorkItem).ToArray()); } string[] fields = this.queryAndLayoutManager.AllLayoutFields.ToArray(); FormatterRefreshData refreshData = new FormatterRefreshData { WorkItemManager = this.workItemManager, QueryWorkItemsBefore = this.queryWorkItems.ToArray(), QueryWorkItemsAfter = afterQueryWorkItems.ToArray(), Layouts = this.queryAndLayoutManager.FinalQueriesAndLayouts.Select(qli => qli.Layout), QueryIsFlat = this.queryAndLayoutManager.FinalQueriesAndLayouts.Select(qli => qli.Query.QueryType == QueryType.List) }; this.formatter.RefreshWorkItems(refreshData, (int qi, int id) => Utilities.QuerySpecificBookmarkNamingFunction(qi)(id), cancellationToken); this.queryWorkItems = afterQueryWorkItems; this.SaveWorkItemsInWorkItemManager(fields, cancellationToken); this.SaveQueryWorkItems(); } return(ans); }