ModelItemExtensions.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Presentation / System / Activities / Presentation / Model / ModelItemExtensions.cs / 1407647 / ModelItemExtensions.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------
namespace System.Activities.Presentation.Model
{ 
    using System;
    using System.Activities.Debugger; 
    using System.Activities.Presentation.Services; 
    using System.Activities.Presentation.View;
    using System.Collections.Generic; 
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Linq;
    using System.Runtime; 
    using System.Text;
    using System.Windows; 
    using System.Windows.Input; 
    using System.Windows.Threading;
 
    public static class ModelItemExtensions
    {
        const int MaxExpandLevel = 5;
        const string rootPath = "Root"; 

        public static EditingContext GetEditingContext(this ModelItem modelItem) 
        { 
            EditingContext result = null;
            IModelTreeItem modelTreeItem = modelItem as IModelTreeItem; 
            if (null != modelTreeItem && null != modelTreeItem.ModelTreeManager)
            {
                result = modelTreeItem.ModelTreeManager.Context;
            } 
            return result;
        } 
 
        internal static ModelItem FindParentModelItem(this ModelItem item, Type parentType)
        { 
            if (null == item)
            {
                throw FxTrace.Exception.ArgumentNull("item");
            } 
            if (null == parentType)
            { 
                throw FxTrace.Exception.ArgumentNull("parentType"); 
            }
 
            ModelItem result = null;
            item = item.Parent;
            while (item != null && !parentType.IsAssignableFrom(item.ItemType))
            { 
                item = item.Parent;
            } 
            if (null != item && parentType.IsAssignableFrom(item.ItemType)) 
            {
                result = item; 
            }
            return result;
        }
 
        internal static bool SwitchKeys( this ModelItemDictionary dictionary, ModelItem oldKey, ModelItem newKey )
        { 
            if (null == dictionary) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("dictionary")); 
            }
            if (null == oldKey)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("oldKey")); 
            }
            if (null == newKey) 
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("newKey"));
            } 
            if (!dictionary.ContainsKey(oldKey))
            {
                throw FxTrace.Exception.AsError( new KeyNotFoundException(null == oldKey.GetCurrentValue() ? "oldKey" : oldKey.GetCurrentValue().ToString()));
            } 
            bool result = false;
            if (!dictionary.ContainsKey(newKey)) 
            { 
                ModelItem value = dictionary[oldKey];
                dictionary.Remove(oldKey); 
                dictionary[newKey] = value;
                result = true;
            }
            return result; 
        }
 
        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", 
           Justification = "This is a TryGet pattern that requires out parameters")]
        internal static bool SwitchKeys(this ModelItemDictionary dictionary, object oldKey, object newKey, out ModelItem newKeyItem) 
        {
            if (null == dictionary)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("dictionary")); 
            }
            if (null == oldKey) 
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("oldKey"));
            } 
            if (null == newKey)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("newKey"));
            } 
            if (!dictionary.ContainsKey(oldKey))
            { 
                throw FxTrace.Exception.AsError( new KeyNotFoundException(oldKey.ToString())); 
            }
            bool result = false; 
            newKeyItem = null;
            if (typeof(ModelItem).IsAssignableFrom(oldKey.GetType()) && typeof(ModelItem).IsAssignableFrom(newKey.GetType()))
            {
                result = SwitchKeys(dictionary, (ModelItem)oldKey, (ModelItem)newKey); 
                newKeyItem = (ModelItem)newKey;
            } 
            else 
            {
                if (typeof(ModelItem).IsAssignableFrom(oldKey.GetType())) 
                {
                    oldKey = ((ModelItem)oldKey).GetCurrentValue();
                    if (null == oldKey)
                    { 
                        throw FxTrace.Exception.AsError( new InvalidOperationException("((ModelItem)oldKey).GetCurrentValue()"));
                    } 
                } 
                if (typeof(ModelItem).IsAssignableFrom(newKey.GetType()))
                { 
                    newKey = ((ModelItem)newKey).GetCurrentValue();
                    if (null == newKey)
                    {
                        throw FxTrace.Exception.AsError(new InvalidOperationException("((ModelItem)newKey).GetCurrentValue()")); 
                    }
                } 
            } 
            if (!dictionary.ContainsKey(newKey))
            { 
                ModelItem value = dictionary[oldKey];
                dictionary.Remove(oldKey);
                dictionary[newKey] = value;
                newKeyItem = dictionary.Keys.First(p => object.Equals(p.GetCurrentValue(), newKey)); 
                result = true;
            } 
            return result; 
        }
 
        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters",
           Justification = "This is a TryGet pattern that requires out parameters")]
        internal static bool TryGetPropertyValue(this ModelItem item, out ModelItemCollection value, params string[] path)
        { 
            ModelItem temp;
            value = null; 
            bool result = TryGetPropertyValue(item, out temp, path); 
            if (null != item)
            { 
                value = (ModelItemCollection)temp;
            }
            return result;
        } 

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", 
           Justification = "This is a TryGet pattern that requires out parameters")] 
        internal static bool TryGetPropertyValue(this ModelItem item, out ModelItemDictionary value, params string[] path)
        { 
            ModelItem temp;
            value = null;
            bool result = TryGetPropertyValue(item, out temp, path);
            if (null != item) 
            {
                value = (ModelItemDictionary)temp; 
            } 
            return result;
        } 

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters",
           Justification = "This is a TryGet pattern that requires out parameters")]
        internal static bool TryGetPropertyValue(this ModelItem item, out ModelItem value, params string[] path) 
        {
            if (null == item) 
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("item"));
            } 
            if (null == path)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("path"));
            } 
            if (path.Length < 1)
            { 
                throw FxTrace.Exception.AsError(new ArgumentException(SR.ModelItemPathArrayShouldNotBeEmpty)); 
            }
            value = item; 
            bool result = true;
            for (int i = 0; i < path.Length && true == result && null != value; ++i)
            {
                ModelProperty property = value.Properties[path[i]]; 
                if (null != property)
                { 
                    value = property.Value; 
                    if (null == value)
                    { 
                        result = false;
                    }
                }
                else 
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.PropertyDoesntExistFormatString, path[i]))); 
                } 
            }
            return result; 
        }

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters",
           Justification = "This is a TryGet pattern that requires out parameters")] 
        internal static bool TrySetPropertyValue(this ModelItem item, object value, out ModelItem wrappedValue, params string[] path)
        { 
            if (null == item) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("item")); 
            }
            if (null == path)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("path")); 
            }
            if (path.Length < 1) 
            { 
                throw FxTrace.Exception.AsError(new ArgumentException(SR.ModelItemPathArrayShouldNotBeEmpty));
            } 
            wrappedValue = null;
            bool result = true;
            for (int i = 0; i < path.Length && true == result; ++i)
            { 
                ModelProperty property = item.Properties[path[i]];
                if (null != property) 
                { 
                    if (i == path.Length - 1)
                    { 
                        if (null != value)
                        {
                            wrappedValue = property.SetValue(value);
                        } 
                        else
                        { 
                            property.ClearValue(); 
                        }
                    } 
                    else
                    {
                        item = property.Value;
                        if (null == item) 
                        {
                            result = false; 
                        } 
                    }
                } 
                else
                {
                    throw FxTrace.Exception.AsError( new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.PropertyDoesntExistFormatString, path[i])));
                } 
            }
            return result; 
        } 

 
        public static string GetModelPath(this ModelItem modelItem)
        {
            if (modelItem == null)
            { 
                return null;
            } 
            StringBuilder sb = new StringBuilder(); 
            bool isValid = true;
            HashSet visited = new HashSet(); 
            // walk up the parent chain and create a modelpath from reverse
            // eg. Root.Foo.Bar.Collectionproperty[3].----
            while (modelItem != null)
            { 
                // paths causing us to get into loops are invalid.
                if (visited.Contains(modelItem)) 
                { 
                    isValid = false;
                    break; 
                }
                // remember the visited.
                visited.Add(modelItem);
                // if parent is collection store just the index 
                if (modelItem.Parent is ModelItemCollection)
                { 
                    sb.Insert(0, "[" + ((ModelItemCollection)modelItem.Parent).IndexOf(modelItem).ToString(CultureInfo.InvariantCulture) + "]"); 
                }
                // if parent is a modelproperty store the property name 
                else if (modelItem.Source != null)
                {
                    sb.Insert(0, "." + modelItem.Source.Name);
                } 
                //Our model path doesnt work with dictionaries
                else if (modelItem.Parent is ModelItemDictionary) 
                { 
                    isValid = false;
                    break; 
                }
                if (modelItem.Source != null)
                {
                    modelItem = modelItem.Source.Parent; 
                }
                else 
                { 
                    modelItem = modelItem.Parent;
                } 
            }
            string s = null;
            if (isValid)
            { 
                sb.Insert(0, rootPath);
                s = sb.ToString(); 
            } 
            return s;
        } 

        public static ModelItem GetModelItemFromPath(string path, ModelItem root)
        {
            if (null == root) 
            {
                throw FxTrace.Exception.AsError(new ArgumentNullException("root")); 
            } 
            if (null == path)
            { 
                throw FxTrace.Exception.AsError(new ArgumentNullException("path"));
            }
            ModelItem foundModelItem = null;
            path = path.Trim(); 
            string[] segments = path.Split('.');
            // process each path. path should atleast be 'Root' and should always  begin with 'Root' 
            if (segments.Length > 0 && segments[0] == rootPath) 
            {
                foundModelItem = root; 
                for (int segmentIndex = 1; segmentIndex < segments.Length; segmentIndex++)
                {
                    string segment = segments[segmentIndex];
                    if (!string.IsNullOrEmpty(segment)) 
                    {
                        ModelItem next = GetModelItemFromSegment(foundModelItem, segment); 
                        if (next != null) 
                        {
                            foundModelItem = next; 
                        }
                        else
                        {
                            foundModelItem = null; 
                            break;
                        } 
                    } 
                    else
                    { 
                        foundModelItem = null;
                        break;
                    }
                } 
            }
            return foundModelItem; 
        } 

        private static ModelItem GetModelItemFromSegment(ModelItem currentModelItem, string segment) 
        {
            ModelItem modelItemFromSegment = null;
            int indexOfSquareBrackets = segment.IndexOf('[');
            // e.g Sequence.Activities[0] segment = "Activities[0]" 
            if (indexOfSquareBrackets > 0)
            { 
                string collectionProperty = segment.Substring(0, indexOfSquareBrackets); 
                // find the value of the collection property
                ModelItemCollection segmentCollection = GetModelItemFromSegment(currentModelItem, collectionProperty) as ModelItemCollection; 
                if (segmentCollection != null)
                {
                    try
                    { 
                        // parse the [index] to find the index
                        string indexString = segment.Substring(indexOfSquareBrackets + 1); 
                        indexString = indexString.Substring(0, indexString.Length - 1); 
                        int index = Int32.Parse(indexString, CultureInfo.InvariantCulture);
                        if (index >= 0 && index < segmentCollection.Count) 
                        {
                            // now index into the collection
                            modelItemFromSegment = segmentCollection[index];
                        } 
                    }
                    // dont crash ever. 
                    catch (FormatException) 
                    {
                    } 
                    catch (OverflowException)
                    {
                    }
                } 
            }
            // e.g SomeFoo.Then segment = "Then" 
            else 
            {
                ModelProperty property = currentModelItem.Properties[segment]; 
                if (property != null)
                {
                    modelItemFromSegment = property.Value;
                } 
            }
            return modelItemFromSegment; 
        } 

        internal static IEnumerable GetParentEnumerator(this ModelItem item) 
        {
            return ModelItemExtensions.GetParentEnumerator(item, null);
        }
 
        internal static IEnumerable GetParentEnumerator(this ModelItem item, Func continueEnumerationPredicate)
        { 
            if (null == item) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("item")); 
            }
            while (null != item.Parent)
            {
                if (null != continueEnumerationPredicate && !continueEnumerationPredicate(item.Parent)) 
                {
                    break; 
                } 
                yield return item.Parent;
                item = item.Parent; 
            }
            yield break;
        }
 
        internal static string GetUniqueName(this ModelItemCollection collection, string nameDefaultPrefix, Func nameGetter)
        { 
            return collection.GetUniqueName(nameDefaultPrefix, nameGetter); 
        }
 
        internal static string GetUniqueName(this ModelItemDictionary dictionary, string nameDefaultPrefix, Func nameGetter)
        {
            if (dictionary != null)
            { 
                return dictionary.Keys.GetUniqueName(nameDefaultPrefix, nameGetter);
            } 
            else 
            {
                throw FxTrace.Exception.ArgumentNull("dictionary"); 
            }
        }

        internal static string GetUniqueName(this IEnumerable collection, string nameDefaultPrefix, Func nameGetter) 
        {
            if (null == collection) 
            { 
                throw FxTrace.Exception.ArgumentNull("collection");
            } 
            if (null == nameDefaultPrefix)
            {
                throw FxTrace.Exception.ArgumentNull("nameDefaultPrefix");
            } 
            if (nameDefaultPrefix.Length == 0)
            { 
                throw FxTrace.Exception.Argument("nameDefaultPrefix", "length == 0"); 
            }
            if (null == nameGetter) 
            {
                throw FxTrace.Exception.ArgumentNull("nameGetter");
            }
 
            var maxId = (int?)collection.
                Where(p => 
                { 
                    var value = nameGetter(p);
                    if (null != value ) 
                    {
                        return (0 == string.Compare(value, 0, nameDefaultPrefix, 0, nameDefaultPrefix.Length, CultureInfo.CurrentCulture, CompareOptions.None));
                    }
                    return false; 
                }).
                Select(p => 
                { 
                    int result = 0;
                    return (int.TryParse(nameGetter(p).Substring(nameDefaultPrefix.Length), out result)) 
                        ? result : 0;
                }).
                OrderByDescending(p => p).
                FirstOrDefault(); 

            int id = maxId.HasValue ? maxId.Value + 1 : 1; 
 
            return string.Format(CultureInfo.CurrentCulture, "{0}{1}", nameDefaultPrefix, id);
        } 

        internal static bool IsAssignableFrom(this ModelItem item) where T : class
        {
            if (null == item) 
            {
                throw FxTrace.Exception.ArgumentNull("item"); 
            } 

            return typeof(T).IsAssignableFrom(item.ItemType); 
        }

        internal static Activity GetRootActivity(this ModelItem item)
        { 
            Object root = item.GetCurrentValue();
            if (root is IDebuggableWorkflowTree) 
            { 
                return ((IDebuggableWorkflowTree)root).GetWorkflowRoot();
            } 
            else
            {
                return root as Activity;
            } 
        }
 
        public static bool IsParentOf(this ModelItem item, ModelItem child) 
        {
            if (null == item) 
            {
                throw FxTrace.Exception.ArgumentNull("item");
            }
            if (null == child) 
            {
                throw FxTrace.Exception.ArgumentNull("child"); 
            } 

            bool isParent = false; 
            child.GetParentEnumerator(p => { isParent = ModelItem.Equals(p, item); return !isParent; }).LastOrDefault();
            return isParent;
        }
 
        public static void Focus(this ModelItem item)
        { 
            Focus(item, MaxExpandLevel); 
        }
 
        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);
        }
 
        private sealed class ModelItemFocusHelper
        { 
            static ModelItemFocusHelper focusTicket = null; 

            ModelItem itemToFocus; 
            int currentLevel;
            bool shouldAbort = false;

            EditingContext context; 
            VirtualizedContainerService containerService;
            WorkflowViewService viewService; 
            DesignerView designerView; 
            ModelItem[] itemsToExpand;
 
            EditingContext Context
            {
                get
                { 
                    if (null == this.context)
                    { 
                        this.context = this.itemToFocus.GetEditingContext(); 
                    }
                    return this.context; 
                }
            }
            VirtualizedContainerService ContainerService
            { 
                get
                { 
                    if (null == this.containerService) 
                    {
                        this.containerService = this.Context.Services.GetService(); 
                    }
                    return this.containerService;
                }
            } 
            WorkflowViewService ViewService
            { 
                get 
                {
                    if (null == this.viewService) 
                    {
                        this.viewService = (WorkflowViewService)this.Context.Services.GetService();
                    }
                    return this.viewService; 
                }
            } 
            DesignerView DesignerView 
            {
                get 
                {
                    if (null == this.designerView)
                    {
                        this.designerView = this.Context.Services.GetService(); 
                    }
                    return this.designerView; 
                } 
            }
 
            Action onContainerPopulatingDelegate;
            Action onElementFocusingDelegate;
            Action onSetDesignerContentVisibilityDelegate;
            Action onForceElementFocusDelegate; 

 
            private ModelItemFocusHelper(ModelItem itemToFocus, int maxExpandLevel) 
            {
                this.itemToFocus = itemToFocus; 
                this.currentLevel = maxExpandLevel;
                this.onContainerPopulatingDelegate = this.OnPopulateContainer;
                this.onElementFocusingDelegate = this.OnFocusElement;
                this.onSetDesignerContentVisibilityDelegate = this.ChangeDesignerViewVisibility; 
                this.onForceElementFocusDelegate = this.OnForceFocusElement;
            } 
 
            public static void Focus(ModelItem itemToFocus, int maxExpandLevel)
            { 
                //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)
                { 
                    // Only cancel previous focus call if it is to focus to other activity.
                    if (!(itemToFocus.GetCurrentValue() is Activity)) 
                    { 
                        return;
                    } 
                    focusTicket.shouldAbort = true;
                }
                //create new focus ticket
                focusTicket = new ModelItemFocusHelper(itemToFocus, maxExpandLevel); 
                //and start its processing as soon as application gets idle
                Dispatcher.CurrentDispatcher.BeginInvoke(new Action((p) => { p.Focus(); }), DispatcherPriority.ContextIdle, focusTicket); 
            } 

            // Entry point method for setting focus. 
            // it is executed exactly once, on application idle event
            // there are 3 basic paths:
            // a) optimistic - element we are looking for, is visible - i bring it into view and set keyboard focus to it
            // b) unlikely - element doesn't have any visual parents - i make it a root designer, wait for it to load and set keyboard focus to it 
            // c) pesimistic/complex - element isn't in the view, moreover, it is located in a tree branch which is not (or is partialy) visible
            void Focus() 
            { 
                //can i continue?
                if (shouldAbort) 
                {
                    return;
                }
 
                //hide the designer view until focus is set
                this.onSetDesignerContentVisibilityDelegate(Visibility.Hidden); 
                //delegate visibility restore for designer view after focus update is complete 
                Dispatcher.CurrentDispatcher.BeginInvoke(this.onSetDesignerContentVisibilityDelegate, DispatcherPriority.ApplicationIdle, Visibility.Visible);
 
                //easy path - if the current designer is available and visible - bring it to view and focus
                if (null != this.itemToFocus.View && ((UIElement)this.itemToFocus.View).IsVisible)
                {
                    this.onElementFocusingDelegate(this.itemToFocus); 
                    return;
                } 
 
                //set selection to the item to focus, so all apropriate designers get a chance to update themselfs before we start expanding - this may
                //result in visual tree change 
                Selection.SelectOnly(this.Context, this.itemToFocus);

                //get items up to the tree root, which can be visualized (have associated designer)
                //include only up to "level" items (avoid expanding whole tree) 
                bool shouldContinue = true;
                int visualItemsCount = 0; 
                var visualItems = this.itemToFocus 
                    .GetParentEnumerator(p => shouldContinue)
                    .Where(p => 
                        {
                            //filter only items with designer attribute
                            bool result = false;
                            var designerType = this.ViewService.GetDesignerType(p.ItemType); 
                            if (null != designerType)
                            { 
                                result = true; 
                                visualItemsCount++;
                                //if designer has Options attribute, check if it always collapsed children - if so, this will be the topmost parent 
                                //(displaying anything above, will never display its children)
                                var options = WorkflowViewService.GetAttribute(designerType);
                                if (null != options && options.AlwaysCollapseChildren && visualItemsCount > 2)
                                { 
                                    shouldContinue = false;
                                } 
                            } 
                            return result;
                        }) 
                    .Take(this.currentLevel)
                    .ToArray();

 

                //nothing to expand, rather unlikely, but handle it anyway 
                if (visualItems.Length == 0) 
                {
                    //reset ticket, to prevent any further calls from executing 
                    ModelItemFocusHelper.focusTicket = null;
                    //force item to be root designer (this is last resort, it is executed only if focusTicket is null)
                    this.onForceElementFocusDelegate();
                    return; 
                }
 
                //get the first parent of an item, which is visible 
                var firstVisibleItem = visualItems.FirstOrDefault(p => null != p.View && ((UIElement)p.View).IsVisible);
 
                bool enqueueFirstExpand = false;

                //is there anything visible in the path between item and its parents?
                if (null != firstVisibleItem) 
                {
                    //yes - limit the amount of items to expand to only designers which are not visible yet 
                    //(include the first visible designer, so algorithm can have a start point with something visible) 
                    this.itemsToExpand = visualItems.TakeWhile(p => firstVisibleItem != p ).Concat( new ModelItem[] { firstVisibleItem} ).ToArray();
                } 
                else
                {
                    //no, nothing is visible yet
                    this.itemsToExpand = visualItems; 
                    enqueueFirstExpand = true;
                    //make the top most parent as root designer 
                    this.DesignerView.MakeRootDesigner(this.itemsToExpand[this.itemsToExpand.Length - 1], false); 
                }
                //delegate Expand call - if nothing is visible yet - onIdle - give new designer time to fully render, if someting is visible - execute immediatelly 
                Dispatcher.CurrentDispatcher.BeginInvoke(new Action( () => { this.Expand(null); }), enqueueFirstExpand ? DispatcherPriority.ContextIdle : DispatcherPriority.Send);
            }

            //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); 
                                    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); 
                                return; 
                            }
                            //the item we want to set focus to, also cannot be displayed as root; 
                            //at this point - simply set selection to given item, check if visibility has changed due to selection change
                            this.Context.Items.SetValue(new Selection(this.itemToFocus));
                            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 themselfs - 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 + ")"); 
                }
            }

            //Populate method is executed by Expand method. It is supposed to bring container element into view, 
            //find the elemennt we are looking for (or at least container which contains it). After bringing contaner into view, it delegates calls to
            //OnPopulateContainer (if we have virutal container) and then to OnFocusElement delegate 
            void Populate(FrameworkElement container) 
            {
                //ensure container is in the view 
                container.BringIntoView();
                //is it virtualized container?
                var virtualContainer = container as VirtualizedContainerService.VirtualizingContainer;
                var viewElement = container as WorkflowViewElement; 
                var modelItem = (null != virtualContainer ?  virtualContainer.ModelItem :
                    (viewElement != null ? viewElement.ModelItem : null)); 
                var dispatchParameter = new object[] { modelItem }; 
                DispatcherPriority priority = DispatcherPriority.Send;
 
                if (null != virtualContainer)
                {
                    priority = DispatcherPriority.ContextIdle;
                    //yes - ensure its content is populated 
                    virtualContainer.Populate();
                    //wait until container content renders (delegate calls to application idle) 
                    Dispatcher.CurrentDispatcher.BeginInvoke(this.onContainerPopulatingDelegate, priority, virtualContainer); 
                }
                //if we have a virtual contianer - we may need to drill further or simply display an element, 
                //otherwise - just try to focus on element (it should be visible, so execute callback immediately)
                Dispatcher.CurrentDispatcher.BeginInvoke(this.onElementFocusingDelegate, priority, dispatchParameter);
            }
 
            void OnPopulateContainer(VirtualizedContainerService.VirtualizingContainer virtualContainer)
            { 
                if (this.shouldAbort) 
                {
                    return; 
                }
                //if this is virutal container, it might contain multiple other virtual containers - i need to find the one
                //which either is a container for item i want to focus, or one which is parent designer for the item i'm looking for
                //look for the container which contains or is a parent of container i look for 
                var target = virtualContainer
                    .ChildContainers 
                    .FirstOrDefault(p => ModelItem.Equals(this.itemToFocus, p.ModelItem) || p.ModelItem.IsParentOf(this.itemToFocus)); 

                //if one is found - populate it and bring it into view 
                if (null != target)
                {
                    target.Populate();
                    target.BringIntoView(); 
                }
            } 
 
            void OnFocusElement(ModelItem currentItem)
            { 
                if (this.shouldAbort)
                {
                    return;
                } 

                //after virtual container is loaded and populated, check if the item i'm looking for is visible 
                if (null != this.itemToFocus.View && ((FrameworkElement)this.itemToFocus.View).IsVisible) 
                {
                    //yes! - it is visible, bring it into view and set focus 
                    ((FrameworkElement)this.itemToFocus.View).BringIntoView();
                    Keyboard.Focus(this.itemToFocus.View as IInputElement);
                    ModelItemFocusHelper.focusTicket = null;
                } 
                else if (null != currentItem)
                { 
                    //no, it still isn't visible - try to expand next level 
                    --this.currentLevel;
                    this.Expand(currentItem); 
                }
                else
                {
                    ModelItemFocusHelper.focusTicket = null; 
                    var displayProperty = this.itemToFocus.Properties["DisplayName"];
                    var displayName = displayProperty == null ? "(unknown)" : displayProperty.ComputedValue.ToString(); 
                    Fx.Assert("OnFocusElement is in invalid state - we should never get here. Item to focus: " + displayName + " (" + this.itemToFocus.ItemType.Name + ")"); 
                }
            } 

            void OnForceFocusElement()
            {
                if (this.shouldAbort) 
                {
                    return; 
                } 
                //if we did exploit all possibilites but model item is still not visible and focused - force it as a root designer
                if (null == ModelItemFocusHelper.focusTicket && (null == this.itemToFocus.View || !((UIElement)this.itemToFocus.View).IsVisible)) 
                {
                    this.DesignerView.MakeRootDesigner(this.itemToFocus, false, false);
                    Dispatcher.CurrentDispatcher.BeginInvoke(this.onElementFocusingDelegate, DispatcherPriority.ContextIdle, this.itemToFocus);
                } 
            }
 
            void ChangeDesignerViewVisibility(Visibility state) 
            {
                if (!this.shouldAbort) 
                {
                    //i can't set visibility to hidden, so in order to avoid flickering, i simply set opacity to very low value -
                    //visual tree is still visible, but user won't notice it.
                    //this.DesignerView.ScrollableContent.Opacity = (state == Visibility.Visible ? 1.0 : 0.01); 
                    Mouse.OverrideCursor = (state == Visibility.Visible ? Cursors.Arrow : Cursors.Wait);
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------
namespace System.Activities.Presentation.Model
{ 
    using System;
    using System.Activities.Debugger; 
    using System.Activities.Presentation.Services; 
    using System.Activities.Presentation.View;
    using System.Collections.Generic; 
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Linq;
    using System.Runtime; 
    using System.Text;
    using System.Windows; 
    using System.Windows.Input; 
    using System.Windows.Threading;
 
    public static class ModelItemExtensions
    {
        const int MaxExpandLevel = 5;
        const string rootPath = "Root"; 

        public static EditingContext GetEditingContext(this ModelItem modelItem) 
        { 
            EditingContext result = null;
            IModelTreeItem modelTreeItem = modelItem as IModelTreeItem; 
            if (null != modelTreeItem && null != modelTreeItem.ModelTreeManager)
            {
                result = modelTreeItem.ModelTreeManager.Context;
            } 
            return result;
        } 
 
        internal static ModelItem FindParentModelItem(this ModelItem item, Type parentType)
        { 
            if (null == item)
            {
                throw FxTrace.Exception.ArgumentNull("item");
            } 
            if (null == parentType)
            { 
                throw FxTrace.Exception.ArgumentNull("parentType"); 
            }
 
            ModelItem result = null;
            item = item.Parent;
            while (item != null && !parentType.IsAssignableFrom(item.ItemType))
            { 
                item = item.Parent;
            } 
            if (null != item && parentType.IsAssignableFrom(item.ItemType)) 
            {
                result = item; 
            }
            return result;
        }
 
        internal static bool SwitchKeys( this ModelItemDictionary dictionary, ModelItem oldKey, ModelItem newKey )
        { 
            if (null == dictionary) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("dictionary")); 
            }
            if (null == oldKey)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("oldKey")); 
            }
            if (null == newKey) 
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("newKey"));
            } 
            if (!dictionary.ContainsKey(oldKey))
            {
                throw FxTrace.Exception.AsError( new KeyNotFoundException(null == oldKey.GetCurrentValue() ? "oldKey" : oldKey.GetCurrentValue().ToString()));
            } 
            bool result = false;
            if (!dictionary.ContainsKey(newKey)) 
            { 
                ModelItem value = dictionary[oldKey];
                dictionary.Remove(oldKey); 
                dictionary[newKey] = value;
                result = true;
            }
            return result; 
        }
 
        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", 
           Justification = "This is a TryGet pattern that requires out parameters")]
        internal static bool SwitchKeys(this ModelItemDictionary dictionary, object oldKey, object newKey, out ModelItem newKeyItem) 
        {
            if (null == dictionary)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("dictionary")); 
            }
            if (null == oldKey) 
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("oldKey"));
            } 
            if (null == newKey)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("newKey"));
            } 
            if (!dictionary.ContainsKey(oldKey))
            { 
                throw FxTrace.Exception.AsError( new KeyNotFoundException(oldKey.ToString())); 
            }
            bool result = false; 
            newKeyItem = null;
            if (typeof(ModelItem).IsAssignableFrom(oldKey.GetType()) && typeof(ModelItem).IsAssignableFrom(newKey.GetType()))
            {
                result = SwitchKeys(dictionary, (ModelItem)oldKey, (ModelItem)newKey); 
                newKeyItem = (ModelItem)newKey;
            } 
            else 
            {
                if (typeof(ModelItem).IsAssignableFrom(oldKey.GetType())) 
                {
                    oldKey = ((ModelItem)oldKey).GetCurrentValue();
                    if (null == oldKey)
                    { 
                        throw FxTrace.Exception.AsError( new InvalidOperationException("((ModelItem)oldKey).GetCurrentValue()"));
                    } 
                } 
                if (typeof(ModelItem).IsAssignableFrom(newKey.GetType()))
                { 
                    newKey = ((ModelItem)newKey).GetCurrentValue();
                    if (null == newKey)
                    {
                        throw FxTrace.Exception.AsError(new InvalidOperationException("((ModelItem)newKey).GetCurrentValue()")); 
                    }
                } 
            } 
            if (!dictionary.ContainsKey(newKey))
            { 
                ModelItem value = dictionary[oldKey];
                dictionary.Remove(oldKey);
                dictionary[newKey] = value;
                newKeyItem = dictionary.Keys.First(p => object.Equals(p.GetCurrentValue(), newKey)); 
                result = true;
            } 
            return result; 
        }
 
        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters",
           Justification = "This is a TryGet pattern that requires out parameters")]
        internal static bool TryGetPropertyValue(this ModelItem item, out ModelItemCollection value, params string[] path)
        { 
            ModelItem temp;
            value = null; 
            bool result = TryGetPropertyValue(item, out temp, path); 
            if (null != item)
            { 
                value = (ModelItemCollection)temp;
            }
            return result;
        } 

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", 
           Justification = "This is a TryGet pattern that requires out parameters")] 
        internal static bool TryGetPropertyValue(this ModelItem item, out ModelItemDictionary value, params string[] path)
        { 
            ModelItem temp;
            value = null;
            bool result = TryGetPropertyValue(item, out temp, path);
            if (null != item) 
            {
                value = (ModelItemDictionary)temp; 
            } 
            return result;
        } 

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters",
           Justification = "This is a TryGet pattern that requires out parameters")]
        internal static bool TryGetPropertyValue(this ModelItem item, out ModelItem value, params string[] path) 
        {
            if (null == item) 
            { 
                throw FxTrace.Exception.AsError( new ArgumentNullException("item"));
            } 
            if (null == path)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("path"));
            } 
            if (path.Length < 1)
            { 
                throw FxTrace.Exception.AsError(new ArgumentException(SR.ModelItemPathArrayShouldNotBeEmpty)); 
            }
            value = item; 
            bool result = true;
            for (int i = 0; i < path.Length && true == result && null != value; ++i)
            {
                ModelProperty property = value.Properties[path[i]]; 
                if (null != property)
                { 
                    value = property.Value; 
                    if (null == value)
                    { 
                        result = false;
                    }
                }
                else 
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.PropertyDoesntExistFormatString, path[i]))); 
                } 
            }
            return result; 
        }

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters",
           Justification = "This is a TryGet pattern that requires out parameters")] 
        internal static bool TrySetPropertyValue(this ModelItem item, object value, out ModelItem wrappedValue, params string[] path)
        { 
            if (null == item) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("item")); 
            }
            if (null == path)
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("path")); 
            }
            if (path.Length < 1) 
            { 
                throw FxTrace.Exception.AsError(new ArgumentException(SR.ModelItemPathArrayShouldNotBeEmpty));
            } 
            wrappedValue = null;
            bool result = true;
            for (int i = 0; i < path.Length && true == result; ++i)
            { 
                ModelProperty property = item.Properties[path[i]];
                if (null != property) 
                { 
                    if (i == path.Length - 1)
                    { 
                        if (null != value)
                        {
                            wrappedValue = property.SetValue(value);
                        } 
                        else
                        { 
                            property.ClearValue(); 
                        }
                    } 
                    else
                    {
                        item = property.Value;
                        if (null == item) 
                        {
                            result = false; 
                        } 
                    }
                } 
                else
                {
                    throw FxTrace.Exception.AsError( new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.PropertyDoesntExistFormatString, path[i])));
                } 
            }
            return result; 
        } 

 
        public static string GetModelPath(this ModelItem modelItem)
        {
            if (modelItem == null)
            { 
                return null;
            } 
            StringBuilder sb = new StringBuilder(); 
            bool isValid = true;
            HashSet visited = new HashSet(); 
            // walk up the parent chain and create a modelpath from reverse
            // eg. Root.Foo.Bar.Collectionproperty[3].----
            while (modelItem != null)
            { 
                // paths causing us to get into loops are invalid.
                if (visited.Contains(modelItem)) 
                { 
                    isValid = false;
                    break; 
                }
                // remember the visited.
                visited.Add(modelItem);
                // if parent is collection store just the index 
                if (modelItem.Parent is ModelItemCollection)
                { 
                    sb.Insert(0, "[" + ((ModelItemCollection)modelItem.Parent).IndexOf(modelItem).ToString(CultureInfo.InvariantCulture) + "]"); 
                }
                // if parent is a modelproperty store the property name 
                else if (modelItem.Source != null)
                {
                    sb.Insert(0, "." + modelItem.Source.Name);
                } 
                //Our model path doesnt work with dictionaries
                else if (modelItem.Parent is ModelItemDictionary) 
                { 
                    isValid = false;
                    break; 
                }
                if (modelItem.Source != null)
                {
                    modelItem = modelItem.Source.Parent; 
                }
                else 
                { 
                    modelItem = modelItem.Parent;
                } 
            }
            string s = null;
            if (isValid)
            { 
                sb.Insert(0, rootPath);
                s = sb.ToString(); 
            } 
            return s;
        } 

        public static ModelItem GetModelItemFromPath(string path, ModelItem root)
        {
            if (null == root) 
            {
                throw FxTrace.Exception.AsError(new ArgumentNullException("root")); 
            } 
            if (null == path)
            { 
                throw FxTrace.Exception.AsError(new ArgumentNullException("path"));
            }
            ModelItem foundModelItem = null;
            path = path.Trim(); 
            string[] segments = path.Split('.');
            // process each path. path should atleast be 'Root' and should always  begin with 'Root' 
            if (segments.Length > 0 && segments[0] == rootPath) 
            {
                foundModelItem = root; 
                for (int segmentIndex = 1; segmentIndex < segments.Length; segmentIndex++)
                {
                    string segment = segments[segmentIndex];
                    if (!string.IsNullOrEmpty(segment)) 
                    {
                        ModelItem next = GetModelItemFromSegment(foundModelItem, segment); 
                        if (next != null) 
                        {
                            foundModelItem = next; 
                        }
                        else
                        {
                            foundModelItem = null; 
                            break;
                        } 
                    } 
                    else
                    { 
                        foundModelItem = null;
                        break;
                    }
                } 
            }
            return foundModelItem; 
        } 

        private static ModelItem GetModelItemFromSegment(ModelItem currentModelItem, string segment) 
        {
            ModelItem modelItemFromSegment = null;
            int indexOfSquareBrackets = segment.IndexOf('[');
            // e.g Sequence.Activities[0] segment = "Activities[0]" 
            if (indexOfSquareBrackets > 0)
            { 
                string collectionProperty = segment.Substring(0, indexOfSquareBrackets); 
                // find the value of the collection property
                ModelItemCollection segmentCollection = GetModelItemFromSegment(currentModelItem, collectionProperty) as ModelItemCollection; 
                if (segmentCollection != null)
                {
                    try
                    { 
                        // parse the [index] to find the index
                        string indexString = segment.Substring(indexOfSquareBrackets + 1); 
                        indexString = indexString.Substring(0, indexString.Length - 1); 
                        int index = Int32.Parse(indexString, CultureInfo.InvariantCulture);
                        if (index >= 0 && index < segmentCollection.Count) 
                        {
                            // now index into the collection
                            modelItemFromSegment = segmentCollection[index];
                        } 
                    }
                    // dont crash ever. 
                    catch (FormatException) 
                    {
                    } 
                    catch (OverflowException)
                    {
                    }
                } 
            }
            // e.g SomeFoo.Then segment = "Then" 
            else 
            {
                ModelProperty property = currentModelItem.Properties[segment]; 
                if (property != null)
                {
                    modelItemFromSegment = property.Value;
                } 
            }
            return modelItemFromSegment; 
        } 

        internal static IEnumerable GetParentEnumerator(this ModelItem item) 
        {
            return ModelItemExtensions.GetParentEnumerator(item, null);
        }
 
        internal static IEnumerable GetParentEnumerator(this ModelItem item, Func continueEnumerationPredicate)
        { 
            if (null == item) 
            {
                throw FxTrace.Exception.AsError( new ArgumentNullException("item")); 
            }
            while (null != item.Parent)
            {
                if (null != continueEnumerationPredicate && !continueEnumerationPredicate(item.Parent)) 
                {
                    break; 
                } 
                yield return item.Parent;
                item = item.Parent; 
            }
            yield break;
        }
 
        internal static string GetUniqueName(this ModelItemCollection collection, string nameDefaultPrefix, Func nameGetter)
        { 
            return collection.GetUniqueName(nameDefaultPrefix, nameGetter); 
        }
 
        internal static string GetUniqueName(this ModelItemDictionary dictionary, string nameDefaultPrefix, Func nameGetter)
        {
            if (dictionary != null)
            { 
                return dictionary.Keys.GetUniqueName(nameDefaultPrefix, nameGetter);
            } 
            else 
            {
                throw FxTrace.Exception.ArgumentNull("dictionary"); 
            }
        }

        internal static string GetUniqueName(this IEnumerable collection, string nameDefaultPrefix, Func nameGetter) 
        {
            if (null == collection) 
            { 
                throw FxTrace.Exception.ArgumentNull("collection");
            } 
            if (null == nameDefaultPrefix)
            {
                throw FxTrace.Exception.ArgumentNull("nameDefaultPrefix");
            } 
            if (nameDefaultPrefix.Length == 0)
            { 
                throw FxTrace.Exception.Argument("nameDefaultPrefix", "length == 0"); 
            }
            if (null == nameGetter) 
            {
                throw FxTrace.Exception.ArgumentNull("nameGetter");
            }
 
            var maxId = (int?)collection.
                Where(p => 
                { 
                    var value = nameGetter(p);
                    if (null != value ) 
                    {
                        return (0 == string.Compare(value, 0, nameDefaultPrefix, 0, nameDefaultPrefix.Length, CultureInfo.CurrentCulture, CompareOptions.None));
                    }
                    return false; 
                }).
                Select(p => 
                { 
                    int result = 0;
                    return (int.TryParse(nameGetter(p).Substring(nameDefaultPrefix.Length), out result)) 
                        ? result : 0;
                }).
                OrderByDescending(p => p).
                FirstOrDefault(); 

            int id = maxId.HasValue ? maxId.Value + 1 : 1; 
 
            return string.Format(CultureInfo.CurrentCulture, "{0}{1}", nameDefaultPrefix, id);
        } 

        internal static bool IsAssignableFrom(this ModelItem item) where T : class
        {
            if (null == item) 
            {
                throw FxTrace.Exception.ArgumentNull("item"); 
            } 

            return typeof(T).IsAssignableFrom(item.ItemType); 
        }

        internal static Activity GetRootActivity(this ModelItem item)
        { 
            Object root = item.GetCurrentValue();
            if (root is IDebuggableWorkflowTree) 
            { 
                return ((IDebuggableWorkflowTree)root).GetWorkflowRoot();
            } 
            else
            {
                return root as Activity;
            } 
        }
 
        public static bool IsParentOf(this ModelItem item, ModelItem child) 
        {
            if (null == item) 
            {
                throw FxTrace.Exception.ArgumentNull("item");
            }
            if (null == child) 
            {
                throw FxTrace.Exception.ArgumentNull("child"); 
            } 

            bool isParent = false; 
            child.GetParentEnumerator(p => { isParent = ModelItem.Equals(p, item); return !isParent; }).LastOrDefault();
            return isParent;
        }
 
        public static void Focus(this ModelItem item)
        { 
            Focus(item, MaxExpandLevel); 
        }
 
        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);
        }
 
        private sealed class ModelItemFocusHelper
        { 
            static ModelItemFocusHelper focusTicket = null; 

            ModelItem itemToFocus; 
            int currentLevel;
            bool shouldAbort = false;

            EditingContext context; 
            VirtualizedContainerService containerService;
            WorkflowViewService viewService; 
            DesignerView designerView; 
            ModelItem[] itemsToExpand;
 
            EditingContext Context
            {
                get
                { 
                    if (null == this.context)
                    { 
                        this.context = this.itemToFocus.GetEditingContext(); 
                    }
                    return this.context; 
                }
            }
            VirtualizedContainerService ContainerService
            { 
                get
                { 
                    if (null == this.containerService) 
                    {
                        this.containerService = this.Context.Services.GetService(); 
                    }
                    return this.containerService;
                }
            } 
            WorkflowViewService ViewService
            { 
                get 
                {
                    if (null == this.viewService) 
                    {
                        this.viewService = (WorkflowViewService)this.Context.Services.GetService();
                    }
                    return this.viewService; 
                }
            } 
            DesignerView DesignerView 
            {
                get 
                {
                    if (null == this.designerView)
                    {
                        this.designerView = this.Context.Services.GetService(); 
                    }
                    return this.designerView; 
                } 
            }
 
            Action onContainerPopulatingDelegate;
            Action onElementFocusingDelegate;
            Action onSetDesignerContentVisibilityDelegate;
            Action onForceElementFocusDelegate; 

 
            private ModelItemFocusHelper(ModelItem itemToFocus, int maxExpandLevel) 
            {
                this.itemToFocus = itemToFocus; 
                this.currentLevel = maxExpandLevel;
                this.onContainerPopulatingDelegate = this.OnPopulateContainer;
                this.onElementFocusingDelegate = this.OnFocusElement;
                this.onSetDesignerContentVisibilityDelegate = this.ChangeDesignerViewVisibility; 
                this.onForceElementFocusDelegate = this.OnForceFocusElement;
            } 
 
            public static void Focus(ModelItem itemToFocus, int maxExpandLevel)
            { 
                //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)
                { 
                    // Only cancel previous focus call if it is to focus to other activity.
                    if (!(itemToFocus.GetCurrentValue() is Activity)) 
                    { 
                        return;
                    } 
                    focusTicket.shouldAbort = true;
                }
                //create new focus ticket
                focusTicket = new ModelItemFocusHelper(itemToFocus, maxExpandLevel); 
                //and start its processing as soon as application gets idle
                Dispatcher.CurrentDispatcher.BeginInvoke(new Action((p) => { p.Focus(); }), DispatcherPriority.ContextIdle, focusTicket); 
            } 

            // Entry point method for setting focus. 
            // it is executed exactly once, on application idle event
            // there are 3 basic paths:
            // a) optimistic - element we are looking for, is visible - i bring it into view and set keyboard focus to it
            // b) unlikely - element doesn't have any visual parents - i make it a root designer, wait for it to load and set keyboard focus to it 
            // c) pesimistic/complex - element isn't in the view, moreover, it is located in a tree branch which is not (or is partialy) visible
            void Focus() 
            { 
                //can i continue?
                if (shouldAbort) 
                {
                    return;
                }
 
                //hide the designer view until focus is set
                this.onSetDesignerContentVisibilityDelegate(Visibility.Hidden); 
                //delegate visibility restore for designer view after focus update is complete 
                Dispatcher.CurrentDispatcher.BeginInvoke(this.onSetDesignerContentVisibilityDelegate, DispatcherPriority.ApplicationIdle, Visibility.Visible);
 
                //easy path - if the current designer is available and visible - bring it to view and focus
                if (null != this.itemToFocus.View && ((UIElement)this.itemToFocus.View).IsVisible)
                {
                    this.onElementFocusingDelegate(this.itemToFocus); 
                    return;
                } 
 
                //set selection to the item to focus, so all apropriate designers get a chance to update themselfs before we start expanding - this may
                //result in visual tree change 
                Selection.SelectOnly(this.Context, this.itemToFocus);

                //get items up to the tree root, which can be visualized (have associated designer)
                //include only up to "level" items (avoid expanding whole tree) 
                bool shouldContinue = true;
                int visualItemsCount = 0; 
                var visualItems = this.itemToFocus 
                    .GetParentEnumerator(p => shouldContinue)
                    .Where(p => 
                        {
                            //filter only items with designer attribute
                            bool result = false;
                            var designerType = this.ViewService.GetDesignerType(p.ItemType); 
                            if (null != designerType)
                            { 
                                result = true; 
                                visualItemsCount++;
                                //if designer has Options attribute, check if it always collapsed children - if so, this will be the topmost parent 
                                //(displaying anything above, will never display its children)
                                var options = WorkflowViewService.GetAttribute(designerType);
                                if (null != options && options.AlwaysCollapseChildren && visualItemsCount > 2)
                                { 
                                    shouldContinue = false;
                                } 
                            } 
                            return result;
                        }) 
                    .Take(this.currentLevel)
                    .ToArray();

 

                //nothing to expand, rather unlikely, but handle it anyway 
                if (visualItems.Length == 0) 
                {
                    //reset ticket, to prevent any further calls from executing 
                    ModelItemFocusHelper.focusTicket = null;
                    //force item to be root designer (this is last resort, it is executed only if focusTicket is null)
                    this.onForceElementFocusDelegate();
                    return; 
                }
 
                //get the first parent of an item, which is visible 
                var firstVisibleItem = visualItems.FirstOrDefault(p => null != p.View && ((UIElement)p.View).IsVisible);
 
                bool enqueueFirstExpand = false;

                //is there anything visible in the path between item and its parents?
                if (null != firstVisibleItem) 
                {
                    //yes - limit the amount of items to expand to only designers which are not visible yet 
                    //(include the first visible designer, so algorithm can have a start point with something visible) 
                    this.itemsToExpand = visualItems.TakeWhile(p => firstVisibleItem != p ).Concat( new ModelItem[] { firstVisibleItem} ).ToArray();
                } 
                else
                {
                    //no, nothing is visible yet
                    this.itemsToExpand = visualItems; 
                    enqueueFirstExpand = true;
                    //make the top most parent as root designer 
                    this.DesignerView.MakeRootDesigner(this.itemsToExpand[this.itemsToExpand.Length - 1], false); 
                }
                //delegate Expand call - if nothing is visible yet - onIdle - give new designer time to fully render, if someting is visible - execute immediatelly 
                Dispatcher.CurrentDispatcher.BeginInvoke(new Action( () => { this.Expand(null); }), enqueueFirstExpand ? DispatcherPriority.ContextIdle : DispatcherPriority.Send);
            }

            //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); 
                                    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); 
                                return; 
                            }
                            //the item we want to set focus to, also cannot be displayed as root; 
                            //at this point - simply set selection to given item, check if visibility has changed due to selection change
                            this.Context.Items.SetValue(new Selection(this.itemToFocus));
                            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 themselfs - 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 + ")"); 
                }
            }

            //Populate method is executed by Expand method. It is supposed to bring container element into view, 
            //find the elemennt we are looking for (or at least container which contains it). After bringing contaner into view, it delegates calls to
            //OnPopulateContainer (if we have virutal container) and then to OnFocusElement delegate 
            void Populate(FrameworkElement container) 
            {
                //ensure container is in the view 
                container.BringIntoView();
                //is it virtualized container?
                var virtualContainer = container as VirtualizedContainerService.VirtualizingContainer;
                var viewElement = container as WorkflowViewElement; 
                var modelItem = (null != virtualContainer ?  virtualContainer.ModelItem :
                    (viewElement != null ? viewElement.ModelItem : null)); 
                var dispatchParameter = new object[] { modelItem }; 
                DispatcherPriority priority = DispatcherPriority.Send;
 
                if (null != virtualContainer)
                {
                    priority = DispatcherPriority.ContextIdle;
                    //yes - ensure its content is populated 
                    virtualContainer.Populate();
                    //wait until container content renders (delegate calls to application idle) 
                    Dispatcher.CurrentDispatcher.BeginInvoke(this.onContainerPopulatingDelegate, priority, virtualContainer); 
                }
                //if we have a virtual contianer - we may need to drill further or simply display an element, 
                //otherwise - just try to focus on element (it should be visible, so execute callback immediately)
                Dispatcher.CurrentDispatcher.BeginInvoke(this.onElementFocusingDelegate, priority, dispatchParameter);
            }
 
            void OnPopulateContainer(VirtualizedContainerService.VirtualizingContainer virtualContainer)
            { 
                if (this.shouldAbort) 
                {
                    return; 
                }
                //if this is virutal container, it might contain multiple other virtual containers - i need to find the one
                //which either is a container for item i want to focus, or one which is parent designer for the item i'm looking for
                //look for the container which contains or is a parent of container i look for 
                var target = virtualContainer
                    .ChildContainers 
                    .FirstOrDefault(p => ModelItem.Equals(this.itemToFocus, p.ModelItem) || p.ModelItem.IsParentOf(this.itemToFocus)); 

                //if one is found - populate it and bring it into view 
                if (null != target)
                {
                    target.Populate();
                    target.BringIntoView(); 
                }
            } 
 
            void OnFocusElement(ModelItem currentItem)
            { 
                if (this.shouldAbort)
                {
                    return;
                } 

                //after virtual container is loaded and populated, check if the item i'm looking for is visible 
                if (null != this.itemToFocus.View && ((FrameworkElement)this.itemToFocus.View).IsVisible) 
                {
                    //yes! - it is visible, bring it into view and set focus 
                    ((FrameworkElement)this.itemToFocus.View).BringIntoView();
                    Keyboard.Focus(this.itemToFocus.View as IInputElement);
                    ModelItemFocusHelper.focusTicket = null;
                } 
                else if (null != currentItem)
                { 
                    //no, it still isn't visible - try to expand next level 
                    --this.currentLevel;
                    this.Expand(currentItem); 
                }
                else
                {
                    ModelItemFocusHelper.focusTicket = null; 
                    var displayProperty = this.itemToFocus.Properties["DisplayName"];
                    var displayName = displayProperty == null ? "(unknown)" : displayProperty.ComputedValue.ToString(); 
                    Fx.Assert("OnFocusElement is in invalid state - we should never get here. Item to focus: " + displayName + " (" + this.itemToFocus.ItemType.Name + ")"); 
                }
            } 

            void OnForceFocusElement()
            {
                if (this.shouldAbort) 
                {
                    return; 
                } 
                //if we did exploit all possibilites but model item is still not visible and focused - force it as a root designer
                if (null == ModelItemFocusHelper.focusTicket && (null == this.itemToFocus.View || !((UIElement)this.itemToFocus.View).IsVisible)) 
                {
                    this.DesignerView.MakeRootDesigner(this.itemToFocus, false, false);
                    Dispatcher.CurrentDispatcher.BeginInvoke(this.onElementFocusingDelegate, DispatcherPriority.ContextIdle, this.itemToFocus);
                } 
            }
 
            void ChangeDesignerViewVisibility(Visibility state) 
            {
                if (!this.shouldAbort) 
                {
                    //i can't set visibility to hidden, so in order to avoid flickering, i simply set opacity to very low value -
                    //visual tree is still visible, but user won't notice it.
                    //this.DesignerView.ScrollableContent.Opacity = (state == Visibility.Visible ? 1.0 : 0.01); 
                    Mouse.OverrideCursor = (state == Visibility.Visible ? Cursors.Arrow : Cursors.Wait);
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK