private void BuildChildItemsList(IConfiguration configuration) { var backlogChildrenList = new List <BacklogChildren>(); AllChildren = new List <WorkItem>(); //keep a hash with the backlog items ids. It implies an additional iteration through the collection, //but we make up for this when searching for parents in constant time rather than linear HashSet <int> backLogIds = new HashSet <int>(); BackLogItems.ForEach(wi => backLogIds.Add(wi.Id)); // Iterate over all backlog items and get the list of child items. // Keep track of the relation between a backlog item and its child item via the BacklogChildren class. foreach (var backLogItem in BackLogItems) { var currentItem = backLogItem; // Get all the work items that the current item points to var childInfos = WorkItemLinkInfos.Where(info => info.SourceId == currentItem.Id).ToList(); // Get the Ids of tht work items var childIds = (from WorkItemLinkInfo info in childInfos select info.TargetId).ToList(); // Get the work items for that ids but only if they are not already in the backlog items list and if they match the child item setting // Note: Uncomment the following line and comment the line after in order to hide backlog items from the child area //var children = WorkItems.Cast<WorkItem>().Where(item => childIds.Contains(item.Id) && !backLogIds.Contains(item.Id) && configuration.ChildItems.Contains(item.Type.Name)).ToList(); var children = WorkItems.Cast <WorkItem>().Where(item => childIds.Contains(item.Id) && configuration.ChildItems.Contains(item.Type.Name)).ToList(); AllChildren.AddRange(children); var backlogChildren = new BacklogChildren(backLogItem, children, configuration.States); backlogChildrenList.Add(backlogChildren); } ApplyChildrenChangesOnUIThread(backlogChildrenList); }
private void ApplyChildrenChangesOnUIThread(List <BacklogChildren> backlogChildrenList) { // The UI binds to BacklogChildren and that's why we must switch to the UI thread before changing the list if (SyncService != null) { if (!SyncService.Value.CheckAccess()) { SyncService.Value.Invoke(new Action <List <BacklogChildren> >(ApplyChildrenChangesOnUIThread), backlogChildrenList); return; } } BacklogChildren.Clear(); foreach (var children in backlogChildrenList) { BacklogChildren.Add(children); FlushWindowsMessageQueue(true); } }
public void ApplyConfiguration(IConfiguration configuration) { if (TeamProjectCollection == null) { return; } if (configuration == null) { return; } if (configuration.QueryId == Guid.Empty) { var errorMessage = StatusService.EnqueueStatusItem("InvalidQuery"); errorMessage.Message = "There is no query defined in the configuration. Please choose a query by clicking \"Edit\""; return; } // Before refreshing the data we should verify whether there are unsaved changes that need to be saved if (!VerifySaveRequest()) { return; } var statusItem = StatusService.EnqueueStatusItem("ApplyConfiguration"); statusItem.Message = string.Format("Applying configuration for team project {0}", TeamProject.Name); statusItem.IsProgressing = true; statusItem.IsProgressIndeterminate = true; // Run the query in order to provide the result data var store = TeamProjectCollection.GetService <WorkItemStore>(); // Get the query based on the Id we keep in the configuration QueryDefinition queryDefinition = SaveGetQueryDefinition(store, configuration.QueryId); Query query = GetQuery(queryDefinition); // Only if the query is a link query we perform the fullblown request for data if ((query != null) && (query.IsLinkQuery)) { // First get the linking information WorkItemLinkInfos = query.RunLinkQuery(); // Get the configured link type in order to respect it when retrieving the work items var linkType = (!string.IsNullOrEmpty(configuration.LinkType)) ? store.WorkItemLinkTypes.FirstOrDefault(type => type.ReferenceName == configuration.LinkType) : null; // Now put all TargetIds into a BatchReadParameterCollection in order to get the work items for the links // Attention: Consider handling the link types correctly var batchReadParams = new BatchReadParameterCollection(); foreach (var linkInfo in WorkItemLinkInfos) { if (linkType == null) { // If there is no link type there is nothing we can check explicitly and therefor we respect any child if (!batchReadParams.Contains(linkInfo.TargetId)) { batchReadParams.Add(new BatchReadParameter(linkInfo.TargetId)); } } else { // Debug.WriteLink("Link: {0} Source: {1} Target: {2} RefName: {3} Forward: {4} Reverse: {5}", linkInfo.LinkTypeId, linkInfo.SourceId, linkInfo.TargetId, linkType.ReferenceName, linkType.ForwardEnd.Id, linkType.ReverseEnd.Id); // We need to respect the link type. if (IsValidLinkInfo(linkInfo, linkType)) { // When the link info is valid according to the current configuration then we consider the work item in our query. if (!batchReadParams.Contains(linkInfo.TargetId)) { batchReadParams.Add(new BatchReadParameter(linkInfo.TargetId)); } } // When the link type is not valid we also do not consider the item. } } // Now construct the query to get the work items string batchQuery = "SELECT {0} FROM WorkItems"; List <string> displayFields = (from FieldDefinition fieldDefinition in query.DisplayFieldList select fieldDefinition.ReferenceName).ToList(); string displayFieldPart = string.Join(",", displayFields.ToArray()); if (batchReadParams.Count != 0) { batchQuery = string.Format(batchQuery, displayFieldPart); // Run the query and remember the results WorkItems = store.Query(batchReadParams, batchQuery); BuildBacklogItemsList(configuration); BuildChildItemsList(configuration); } else { ApplyChildrenChangesOnUIThread(new List <BacklogChildren>()); } } else { WorkItemLinkInfos = null; WorkItems = query != null?query.RunQuery() : null; if (AllChildren != null) { AllChildren.Clear(); } if (BacklogChildren.Count > 0) { BacklogChildren.Clear(); } if (BackLogItems != null) { BackLogItems.Clear(); } } PrepareTransitionsMap(configuration); OnConfigurationApplied(); }