internal static void Focus(ModelItem itemToFocus, int maxExpandLevel, bool shouldGetKeyboardFocus, Rect rectToBringIntoView) { // Check if this model item exist in the model tree IModelTreeItem modelTreeItem = itemToFocus as IModelTreeItem; if (modelTreeItem != null) { // If this model item doesn't exist in the tree, don't do anything, // chances are it's an activity that has been deleted. if (!IsRootedAt(itemToFocus, modelTreeItem.ModelTreeManager.Root) && !(itemToFocus is FakeModelItemImpl)) { return; } } //if there is another focus operation in progress, mark it so it would abort itself on next OnContextIdle processing - //we don't want to multiple elements racing for keyboard focus if (null != focusTicket) { focusTicket.shouldAbort = true; } //create new focus ticket focusTicket = new ModelItemFocusHelper(itemToFocus, maxExpandLevel, shouldGetKeyboardFocus, rectToBringIntoView); //and start its processing as soon as application gets idle Dispatcher.CurrentDispatcher.BeginInvoke(new Action <ModelItemFocusHelper>((p) => { p.Focus(); }), DispatcherPriority.ContextIdle, focusTicket); }
public static void Focus(this ModelItem item, int level) { if (null == item) { throw FxTrace.Exception.ArgumentNull("item"); } if (level < 1) { throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("level")); } ModelItemFocusHelper.Focus(item, level); }
//Expand method is executed repeatadly until maximum expand level is reached. it iterates through the model item tree //(from child up to MaximumExpandLevel parents) and tries to find first visible designer and populate it with content //If one elemnt is visited twice (denoted by currentItem argument) it means that expansion failed - (i.e. element is collapsed), //so i try to set that element as root designer and restart algoritm with that designer beeing new root void Expand(ModelItem currentItem) { //can i continue? if (this.shouldAbort) { return; } //stop condition - prevents infinite loop (the method is delegated into dispatcher, so it would never cause stack overflow if (0 > this.currentLevel) { ModelItemFocusHelper.focusTicket = null; return; } //browse direct parents, and Populate the fist one which is visible for (int index = 0; null != this.itemsToExpand && index < this.itemsToExpand.Length; ++index) { //is given parent visible? (it would return container for given model item) var container = this.ContainerService.QueryContainerForItem(this.itemsToExpand[index]); if (null != container) { //check if container we are trying to expand is not the same as the one in previous iteration //if it isn't --> populate its content if (!ModelItem.Equals(currentItem, this.itemsToExpand[index])) { this.Populate(container); return; } //if it is --> it means it is collapsed and further expand doesn't make sense. else if (null != currentItem) { int j = 0; //get index of item which we've tried to expand recently for (; j < this.itemsToExpand.Length; ++j) { if (ModelItem.Equals(this.itemsToExpand[j], currentItem)) { break; } } //starting at that point, see if given item can be a breadcrumb root for (int skipLevel = 0; j >= 0; --j) { currentItem = this.itemsToExpand[j]; //if it can - make it a new breadcrumb root and restart if (this.viewService.ShouldAppearOnBreadCrumb(currentItem, true)) { //make that designer a new root (don't set selection) this.DesignerView.MakeRootDesigner(currentItem, false); //and try to set focus with less maximum expand level, assuming that current designer is now expanded ModelItemFocusHelper.Focus(this.itemToFocus, this.currentLevel - skipLevel, this.shouldGetKeyboardFocus); return; } ++skipLevel; } //nothing in parent list can be made a breadcrumb, try set item which is supposed to get focus as a root if (this.viewService.ShouldAppearOnBreadCrumb(this.itemToFocus, true)) { this.DesignerView.MakeRootDesigner(this.itemToFocus, false); ModelItemFocusHelper.Focus(this.itemToFocus, 1, this.shouldGetKeyboardFocus); return; } //the item we want to set focus to, also cannot be displayed as root; //at this point - simply set selection to the current item, check if visibility has changed due to selection change this.Context.Items.SetValue(new Selection(currentItem)); Dispatcher.CurrentDispatcher.BeginInvoke(this.onElementFocusingDelegate, DispatcherPriority.ContextIdle, currentItem); //the final check - if item is still not visible, force it to be Dispatcher.CurrentDispatcher.BeginInvoke(this.onForceElementFocusDelegate, DispatcherPriority.ContextIdle); return; } } } ModelItemFocusHelper.focusTicket = null; //if we end up here and itemsToExpand is not null - something is wrong... //it is possible that algorithm stops here and itemsToExpand is null - this would be scenario when user tries to set focus to model item which cannot be //visualized and doesn't have any visual parent - i.e. Service or ActivityBuilder (they have a child property Body which can be visualized, but themselves - are not) if (null != this.itemsToExpand) { var displayProperty = this.itemToFocus.Properties["DisplayName"]; var displayName = displayProperty == null ? "(unknown)" : displayProperty.ComputedValue.ToString(); Fx.Assert("Expand is in invalid state - we should never end up here. Item to focus: " + displayName + " (" + this.itemToFocus.ItemType.Name + ")"); } }
internal static void Highlight(this ModelItem item, Rect rectToBringIntoView) { ModelItemFocusHelper.Focus(item, MaxExpandLevel, false, rectToBringIntoView); }
internal static void Highlight(this ModelItem item) { ModelItemFocusHelper.Focus(item, MaxExpandLevel, false, Rect.Empty); }