1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
5 namespace System.Activities.Presentation.Model
8 using System.Activities.Debugger;
9 using System.Activities.Expressions;
10 using System.Activities.Presentation.Annotations;
11 using System.Activities.Presentation.Converters;
12 using System.Activities.Presentation.Hosting;
13 using System.Activities.Presentation.Internal.PropertyEditing;
14 using System.Activities.Presentation.PropertyEditing;
15 using System.Activities.Presentation.Services;
16 using System.Activities.Presentation.View;
17 using System.Activities.Presentation.Xaml;
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Globalization;
22 using System.Reflection;
24 using System.ServiceModel.Activities;
26 using System.Windows.Documents;
27 using System.Windows.Input;
28 using System.Windows.Threading;
29 using Microsoft.Activities.Presentation;
31 // The main class for search. This class will walkthrough the model item tree to build a TextImage.
32 // And it will access ObjectToSourceLocationMapping with a specific SourceLocation to get a ModelItem
34 class ModelSearchServiceImpl : ModelSearchService
36 const int StartIndexUnchangeMark = -1;
37 const string DisplayNamePropertyName = "DisplayName";
38 EditingContext editingContext;
39 ModelService modelService;
40 WorkflowDesigner designer;
41 List<SearchableEntry> entries = new List<SearchableEntry>();
42 Dictionary<int, SearchableEntry> textImageIndexEntryMapping = new Dictionary<int, SearchableEntry>();
44 HashSet<Object> alreadyVisitedObjects = new HashSet<Object>();
45 HashSet<object> objectsOnDesinger = new HashSet<object>();
47 ModelItem lastNavigatedItem;
48 bool isModelTreeChanged;
49 ModelItem itemToFocus;
50 AdornerLayer adornerLayer;
51 SearchToolTipAdorner toolTipAdorner;
52 WorkflowViewElement lastWorkflowViewElement;
54 public ModelSearchServiceImpl(WorkflowDesigner designer)
58 throw FxTrace.Exception.AsError(new ArgumentNullException("designer"));
60 this.designer = designer;
61 this.editingContext = this.designer.Context;
63 this.editingContext.Services.Subscribe<ModelService>(new SubscribeServiceCallback<ModelService>(this.OnModelServiceAvailable));
64 this.editingContext.Services.Subscribe<DesignerView>(new SubscribeServiceCallback<DesignerView>(this.OnDesignerViewAvailable));
65 this.editingContext.Services.Subscribe<ModelTreeManager>(new SubscribeServiceCallback<ModelTreeManager>(this.OnModelTreeManagerAvailable));
66 this.editingContext.Items.Subscribe<Selection>(this.OnSelectionChanged);
68 // At the first time, we should generate the TextImage.
69 this.isModelTreeChanged = true;
72 void OnEditingScopeCompleted(object sender, EditingScopeEventArgs e)
74 this.isModelTreeChanged = true;
77 void OnSelectionChanged(Selection selection)
79 if (selection.PrimarySelection != this.lastNavigatedItem)
81 this.isModelTreeChanged = true;
85 // Listen to the mouse down in designer and close tooltip.
86 void OnDesignerSurfaceMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
88 RemoveToolTipAdorner();
91 bool ShouldIgnore(ModelProperty property)
93 // Since we have searched each variable. We can strip out "Variables" property here.
94 // It's valid to hardcode "Variables" property. That's the way how variable designer get variables.
95 // We should strip out 'DisplayName', since it is searched at the beginning.
96 // We strip out 'Id', since it's a property from the Activity Base class, but never used in design time.
97 return string.Equals(property.Name, "Variables", StringComparison.Ordinal)
98 || string.Equals(property.Name, DisplayNamePropertyName, StringComparison.Ordinal)
99 || string.Equals(property.Name, "Id", StringComparison.Ordinal);
102 public override TextImage GenerateTextImage()
104 RemoveToolTipAdorner();
106 // If the modelitem tree was not changed since last time we generated the text image,
107 // return the original TextImage and set the StartIndex to StartIndexUnchangeMark
108 // means VS should use their own index.
109 if (!this.isModelTreeChanged)
111 textImage.StartLineIndex = StartIndexUnchangeMark;
114 this.entries.Clear();
115 this.textImageIndexEntryMapping.Clear();
117 IEnumerable<ModelItem> itemsToSearch = this.GetItemsOnDesigner(preOrder: true, excludeRoot: true, excludeErrorActivity: true, excludeExpression: true, includeOtherObjects: false);
118 foreach (ModelItem item in itemsToSearch)
120 this.objectsOnDesinger.Add(item.GetCurrentValue());
123 Selection selection = this.editingContext.Items.GetValue<Selection>();
124 int startIndex = StartIndexUnchangeMark;
126 // If and only if root is selected, start search from the beginning.
127 if (selection.SelectionCount == 1 && selection.PrimarySelection == modelService.Root)
132 AddEntriesForArguments(selection, ref startIndex);
133 foreach (ModelItem modelItem in itemsToSearch)
135 // Do this check to make sure we start from the topmost selected item.
136 if (startIndex == StartIndexUnchangeMark)
138 if (selection.SelectedObjects.Contains(modelItem) && modelItem != this.lastNavigatedItem)
140 // set the search start index to the next location of the current focus.
145 // Add the DisplayName property first.
146 ModelProperty displayNameProperty = modelItem.Properties[DisplayNamePropertyName];
147 if (displayNameProperty != null)
149 AddEntriesForProperty(displayNameProperty, modelItem, null);
151 foreach (ModelProperty modelProperty in modelItem.Properties)
153 if (!ShouldIgnore(modelProperty))
155 AddEntriesForProperty(modelProperty, modelItem, null);
158 AddEntriesForVariables(modelItem);
161 AddBrowsableProperties(this.modelService.Root);
163 List<string> searchableTexts = new List<string>();
164 int textImageIndex = 0;
165 foreach (SearchableEntry entry in entries)
167 string text = entry.Text;
173 foreach (string line in text.Split(new string[] { Environment.NewLine, "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries))
175 this.textImageIndexEntryMapping.Add(textImageIndex, entry);
176 searchableTexts.Add(line);
181 textImage = new TextImage()
183 StartLineIndex = startIndex,
184 Lines = searchableTexts
187 this.isModelTreeChanged = false;
191 private void OnModelServiceAvailable(ModelService modelService)
193 this.modelService = modelService;
196 private void OnDesignerViewAvailable(DesignerView designerView)
198 designerView.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.OnDesignerSurfaceMouseLeftButtonDown), true);
201 private void OnModelTreeManagerAvailable(ModelTreeManager modelTreeManager)
203 modelTreeManager.EditingScopeCompleted += new EventHandler<EditingScopeEventArgs>(OnEditingScopeCompleted);
206 private void RemoveToolTipAdorner()
208 if (this.toolTipAdorner != null)
210 // remove the adorner on the previous hit item.
211 this.adornerLayer.Remove(this.toolTipAdorner);
212 this.toolTipAdorner = null;
213 this.lastWorkflowViewElement.CustomItemStatus = null;
217 internal IEnumerable<ModelItem> GetItemsOnDesigner(bool preOrder, bool excludeRoot, bool excludeErrorActivity, bool excludeExpression, bool includeOtherObjects)
219 WorkflowViewService viewService = this.WorkflowViewService;
220 IList<ModelItem> items =
221 ModelTreeManager.DepthFirstSearch(modelService.Root,
224 // Only find items on the designer surface.
225 return includeOtherObjects || (typeof(WorkflowViewElement).IsAssignableFrom(viewService.GetDesignerType(type)));
227 delegate(ModelItem modelItem)
229 return !(excludeExpression && modelItem != null && typeof(ITextExpression).IsAssignableFrom(modelItem.ItemType));
233 // ModelItemKeyValuePair is associated with CaseDesigner.
234 // So ModelItemKeyValuePair will be returned even if they are not really Cases.
235 // Those ModelItemKeyValuePairs need to be excluded.
236 IEnumerable<ModelItem> itemsToSearch = null;
237 if (!excludeErrorActivity)
239 itemsToSearch = items.Where<ModelItem>(item => !ModelUtilities.IsModelItemKeyValuePair(item.ItemType)
240 || ModelUtilities.IsSwitchCase(item));
244 itemsToSearch = items.Where<ModelItem>(item =>
245 (!ModelUtilities.IsModelItemKeyValuePair(item.ItemType) || ModelUtilities.IsSwitchCase(item))
246 && !IsErrorActivity(item));
250 itemsToSearch = itemsToSearch.Except<ModelItem>(new ModelItem[] { modelService.Root });
252 return itemsToSearch;
255 static private bool IsErrorActivity(ModelItem item)
257 Type type = item.ItemType;
258 if (type.IsGenericType)
260 return (typeof(ErrorActivity<>) == type.GetGenericTypeDefinition());
263 return (type == typeof(ErrorActivity));
266 internal static string ExpressionToString(object expression)
268 ITextExpression expr = expression as ITextExpression;
269 return (expr != null) ? expr.ExpressionText : expression.ToString();
272 SearchableEntry CreateSearchableEntry(SearchableEntryOption entryType,
273 ModelItem item, ModelProperty property, string text, string propertyPath)
275 return new SearchableEntry()
277 LineNumber = index++,
278 SearchableEntryType = entryType,
280 ModelProperty = property,
282 PropertyPath = propertyPath
286 void AddEntriesForVariables(ModelItem modelItem)
288 ModelItemCollection variables = VariableHelper.GetVariableCollection(modelItem);
289 if (variables != null)
291 foreach (ModelItem variable in variables)
293 entries.Add(CreateSearchableEntry(SearchableEntryOption.Variable, variable, null,
294 TypeNameHelper.GetDisplayName(variable.Properties[DesignTimeVariable.VariableTypeProperty].ComputedValue as Type, false), null));
296 entries.Add(CreateSearchableEntry(SearchableEntryOption.Variable, variable, null,
297 variable.Properties[DesignTimeVariable.VariableNameProperty].ComputedValue.ToString(), null));
299 object propertyValue = variable.Properties[DesignTimeVariable.VariableDefaultProperty].ComputedValue;
301 if (propertyValue != null)
303 entries.Add(CreateSearchableEntry(SearchableEntryOption.Variable, variable, null,
304 ExpressionToString(propertyValue), null));
307 if (this.editingContext.Services.GetService<DesignerConfigurationService>().AnnotationEnabled)
309 string annotationText = (string)variable.Properties[Annotation.AnnotationTextPropertyName].ComputedValue;
310 if (!string.IsNullOrEmpty(annotationText))
312 entries.Add(CreateSearchableEntry(SearchableEntryOption.Variable, variable, null, annotationText, null));
319 private void AddEntriesForPropertyReference(string valueText, ModelItem modelItem,
320 ModelProperty property, SearchableEntryOption entryType, string propertyPath)
322 entries.Add(CreateSearchableEntry(entryType, modelItem, property, valueText, propertyPath));
325 private void AddEntriesForPropertyValue(object value, ModelItem modelItem,
326 ModelProperty property, SearchableEntryOption entryType, string propertyPath)
328 // be ready for recursively visit all sub properties.
329 alreadyVisitedObjects.Clear();
330 IList<string> texts = GetSearchableStrings(value);
333 foreach (string valueText in texts)
335 entries.Add(CreateSearchableEntry(entryType, modelItem, property, valueText, propertyPath));
340 void AddBrowsableProperties(ModelItem modelItem)
342 foreach (ModelProperty property in modelItem.Properties)
344 if (property.IsBrowsable)
346 this.AddEntriesForProperty(property, modelItem, null);
352 void AddEntriesForArguments(Selection selection, ref int startIndex)
354 ModelProperty argumentsProperty = this.modelService.Root.Properties["Properties"];
355 if (argumentsProperty == null)
359 ModelItemCollection arguments = argumentsProperty.Collection;
360 if (arguments != null)
362 ModelItem selectedArgument = this.GetTopmostSelectedArgument(selection, arguments);
363 foreach (ModelItem argument in arguments)
365 // Do this check to make sure we start from the topmost selected item.
366 if (startIndex == StartIndexUnchangeMark && argument == selectedArgument && argument != lastNavigatedItem)
370 entries.Add(CreateSearchableEntry(SearchableEntryOption.Argument, argument, null,
371 TypeNameHelper.GetDisplayName(argument.Properties["Type"].ComputedValue as Type, false), null));
373 entries.Add(CreateSearchableEntry(SearchableEntryOption.Argument, argument, null,
374 argument.Properties[DesignTimeArgument.ArgumentNameProperty].ComputedValue.ToString(), null));
376 IList<string> argumentValues = GetSearchableStrings(argument.Properties[DesignTimeArgument.ArgumentDefaultValueProperty].ComputedValue);
377 if (argumentValues.Count == 1)
379 AddEntriesForPropertyValue(argumentValues[0],
380 argument, null, SearchableEntryOption.Argument, null);
383 if (this.editingContext.Services.GetService<DesignerConfigurationService>().AnnotationEnabled)
385 string annotationText = (string)argument.Properties[Annotation.AnnotationTextPropertyName].ComputedValue;
386 if (!string.IsNullOrEmpty(annotationText))
388 entries.Add(CreateSearchableEntry(SearchableEntryOption.Argument, argument, null, annotationText, null));
395 private ModelItem GetTopmostSelectedArgument(Selection selection, ModelItemCollection arguments)
397 foreach (ModelItem argument in arguments)
399 foreach (ModelItem candidateArgument in selection.SelectedObjects)
401 if (candidateArgument.ItemType == typeof(DesignTimeArgument))
403 // since for arguments, the selection is not the modelitem, it is the fakemodelitem, we cannot do a
404 // simple reference comparing to find the selected argument.
405 DesignTimeArgument designTimeArgument = candidateArgument.GetCurrentValue() as DesignTimeArgument;
406 if (designTimeArgument.ReflectedObject == argument)
416 IList<string> GetSearchableStrings(object computedValue)
418 List<string> results = new List<string>();
419 if (computedValue == null || this.objectsOnDesinger.Contains(computedValue))
424 Type type = computedValue.GetType();
425 if (type.IsPrimitive || computedValue is string || type.IsEnum || computedValue is Uri)
427 return new List<string>() { computedValue.ToString() };
430 SearchableStringConverterAttribute attribute =
431 ExtensibilityAccessor.GetAttribute<SearchableStringConverterAttribute>(type);
433 if (attribute == null)
435 // try its generic type.
436 if (type.IsGenericType)
438 Type generictype = type.GetGenericTypeDefinition();
439 attribute = ExtensibilityAccessor.GetAttribute<SearchableStringConverterAttribute>(generictype);
443 if (attribute != null)
445 Type converterType = Type.GetType(attribute.ConverterTypeName);
446 if (converterType.IsGenericTypeDefinition)
448 converterType = converterType.MakeGenericType(computedValue.GetType().GetGenericArguments());
450 SearchableStringConverter converter = Activator.CreateInstance(converterType) as SearchableStringConverter;
451 return converter.Convert(computedValue);
454 // don't have an direct converter? and is a collection, then let's try convert each member.
455 if (computedValue is IEnumerable)
457 foreach (object value in computedValue as IEnumerable)
459 results.AddRange(GetSearchableStrings(value));
464 // Already tried all the options, let's do a recursive search.
465 alreadyVisitedObjects.Add(computedValue);
466 PropertyInfo[] properties = type.GetProperties();
467 foreach (PropertyInfo property in properties)
469 object propertyValue = property.GetValue(computedValue, null);
470 if (!alreadyVisitedObjects.Contains(propertyValue))
472 results.AddRange(GetSearchableStrings(propertyValue));
478 void AddEntriesForProperty(ModelProperty property, ModelItem modelItem, string propertyPath)
480 if (!string.IsNullOrEmpty(propertyPath))
483 propertyPath += property.Name;
487 propertyPath = property.Name;
490 entries.Add(CreateSearchableEntry(
491 SearchableEntryOption.Property, modelItem, property, TypeNameHelper.GetDisplayName(property.PropertyType, false), propertyPath));
493 entries.Add(CreateSearchableEntry(
494 SearchableEntryOption.Property, modelItem, property, property.Name, propertyPath));
496 if (property.ComputedValue != null)
498 PropertyValueEditor propertyValueEditor = null;
501 propertyValueEditor = ExtensibilityAccessor.GetSubPropertyEditor(property);
503 catch (TargetInvocationException exception)
505 // To workaround 181412.If the current property's property type is a generic type and the activity
506 // is also a generic type Calling to ExtensibilityAccessor.GetSubPropertyEditor will get this exception.
507 if (exception.InnerException is ArgumentException)
509 propertyValueEditor = null;
512 if (propertyValueEditor != null)
514 IList<ModelProperty> properties = ExtensibilityAccessor.GetSubProperties(property);
515 foreach (ModelProperty propertyItem in properties)
517 AddEntriesForProperty(propertyItem, modelItem, propertyPath);
522 // We don't search the value of an expandable property.
523 AddEntriesForPropertyValue(property.ComputedValue, modelItem, property, SearchableEntryOption.Property, propertyPath);
526 else if (property.Reference != null)
528 AddEntriesForPropertyReference(property.Reference, modelItem, property, SearchableEntryOption.Property, propertyPath);
532 public ModelItem FindModelItem(int startLine, int startColumn, int endLine, int endColumn)
534 SourceLocation sourceLocation = new SourceLocation(/* fileName = */ null, startLine, startColumn, endLine, endColumn);
535 return designer.ObjectToSourceLocationMapping.FindModelItem(sourceLocation);
538 public ModelItem FindModelItemOfViewState(int startLine, int startColumn, int endLine, int endColumn)
540 SourceLocation sourceLocation = new SourceLocation(/* fileName = */ null, startLine, startColumn, endLine, endColumn);
541 return designer.ObjectToSourceLocationMapping.FindModelItemOfViewState(sourceLocation);
544 public SourceLocation FindSourceLocation(ModelItem modelItem)
546 return designer.ObjectToSourceLocationMapping.FindSourceLocation(modelItem);
549 public IEnumerable<object> GetObjectsWithSourceLocation()
551 return designer.ObjectToSourceLocationMapping.GetObjectsWithSourceLocation();
554 private ModelItem FindModelItemForNavigate(int startLine, int startColumn, int endLine, int endColumn)
556 // If we search ModelItem first, we will not have a chance to search ViewState because
557 // we will always get an ModelItem, at least the out-most Activity.
558 ModelItem modelItem = this.FindModelItemOfViewState(startLine, startColumn, endLine, endColumn);
559 if (modelItem != null)
564 return this.FindModelItem(startLine, startColumn, endLine, endColumn);
567 public override bool NavigateTo(int startLine, int startColumn, int endLine, int endColumn)
569 ModelItem itemToFocus = this.FindModelItemForNavigate(startLine, startColumn, endLine, endColumn);
571 return this.NavigateTo(itemToFocus);
574 // Navigate to a ModelItem with the specified location in TextImage. This is for Find Next.
575 public override bool NavigateTo(int location)
577 if (location < 0 || location >= this.textImageIndexEntryMapping.Count)
582 SearchableEntry entry = this.textImageIndexEntryMapping[location];
583 return NavigateTo(entry);
586 public bool NavigateTo(ModelItem itemToFocus)
588 if (itemToFocus == null)
593 SearchableEntry entry = CreateSearchableEntryForArgumentOrVariable(itemToFocus);
596 return this.NavigateTo(entry);
599 itemToFocus = this.FindModelItemToFocus(itemToFocus);
606 private static SearchableEntry CreateSearchableEntryNoRecursive(ModelItem modelItem)
608 if (typeof(DynamicActivityProperty).IsAssignableFrom(modelItem.ItemType))
610 return new SearchableEntry
612 SearchableEntryType = SearchableEntryOption.Argument,
613 ModelItem = modelItem
616 else if (typeof(Variable).IsAssignableFrom(modelItem.ItemType))
618 return new SearchableEntry
620 SearchableEntryType = SearchableEntryOption.Variable,
621 ModelItem = modelItem
628 private static SearchableEntry CreateSearchableEntryForArgumentOrVariable(ModelItem itemToFocus)
630 SearchableEntry entry = null;
631 ModelUtilities.ReverseTraverse(itemToFocus, (ModelItem modelItem) =>
633 entry = CreateSearchableEntryNoRecursive(modelItem);
634 return (entry == null);
639 private bool NavigateTo(SearchableEntry entry)
641 if (entry.SearchableEntryType == SearchableEntryOption.Variable)
643 itemToFocus = entry.ModelItem.Parent.Parent;
644 HighlightModelItem(itemToFocus);
645 this.lastNavigatedItem = itemToFocus;
646 var designerView = this.editingContext.Services.GetService<DesignerView>();
647 // Open the variable designer.
648 designerView.CheckButtonVariables();
649 designerView.variables1.SelectVariable(entry.ModelItem);
651 else if (entry.SearchableEntryType == SearchableEntryOption.Argument)
653 itemToFocus = this.modelService.Root;
654 HighlightModelItem(itemToFocus);
655 var designerView = this.editingContext.Services.GetService<DesignerView>();
656 // Open the argument designer.
657 designerView.CheckButtonArguments();
658 designerView.arguments1.SelectArgument(entry.ModelItem);
659 this.lastNavigatedItem = entry.ModelItem;
663 itemToFocus = entry.ModelItem;
664 HighlightModelItem(itemToFocus);
665 this.lastNavigatedItem = itemToFocus;
666 ICommandService commandService = this.editingContext.Services.GetService<ICommandService>();
667 if (commandService != null)
669 commandService.ExecuteCommand(CommandValues.ShowProperties, null);
672 PropertyInspector propertiesGrid = this.designer.PropertyInspectorView as PropertyInspector;
673 propertiesGrid.SelectPropertyByPath(entry.PropertyPath);
674 if (ShouldShowSearchToolTip(itemToFocus))
676 Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
678 WorkflowViewElement viewElement = itemToFocus.View as WorkflowViewElement;
679 if (viewElement != null)
681 this.adornerLayer = AdornerLayer.GetAdornerLayer(viewElement as WorkflowViewElement);
682 if (this.adornerLayer != null)
684 DesignerView designerView = this.editingContext.Services.GetService<DesignerView>();
685 string toolTipText = string.Format(CultureInfo.CurrentUICulture, SR.SearchHintText, entry.ModelProperty.Name);
686 this.toolTipAdorner = new SearchToolTipAdorner(viewElement, designerView, toolTipText);
688 viewElement.CustomItemStatus = "SearchToolTip=" + toolTipText;
689 this.lastWorkflowViewElement = viewElement;
691 this.adornerLayer.Add(this.toolTipAdorner);
694 }), DispatcherPriority.ApplicationIdle);
701 private bool ShouldShowSearchToolTip(ModelItem item)
703 return !typeof(WorkflowService).IsAssignableFrom(item.ItemType)
704 && !typeof(ActivityBuilder).IsAssignableFrom(item.ItemType);
707 private void HighlightModelItem(ModelItem itemToFocus)
709 DesignerView designerView = this.editingContext.Services.GetService<DesignerView>();
710 double width = 0.0, height = 0.0;
711 Rect rectToBringIntoView;
712 FrameworkElement fe = (FrameworkElement)itemToFocus.View;
715 width = Math.Min(fe.RenderSize.Width, designerView.ScrollViewer.ViewportWidth);
716 height = Math.Min(fe.RenderSize.Height, designerView.ScrollViewer.ViewportHeight);
717 rectToBringIntoView = new Rect(0, 0, width, height);
721 rectToBringIntoView = Rect.Empty;
723 itemToFocus.Highlight(rectToBringIntoView);
726 private ModelItem FindModelItemToFocus(ModelItem itemToFocus)
728 WorkflowViewService viewService = this.WorkflowViewService;
729 if (viewService == null || itemToFocus == null)
734 ModelUtilities.ReverseTraverse(itemToFocus, (ModelItem modelItem) =>
736 if (modelItem == null)
742 // if the item has Designer, we assume it can get focus.
743 if (CanFocusOnModelItem(modelItem, viewService))
745 itemToFocus = modelItem;
757 private WorkflowViewService WorkflowViewService
761 return (WorkflowViewService)this.editingContext.Services.GetService<ViewService>();
765 private static bool CanFocusOnModelItem(ModelItem itemToFocus, WorkflowViewService viewService)
767 Fx.Assert(itemToFocus != null && viewService != null, "null argument");
769 if (typeof(ITextExpression).IsAssignableFrom(itemToFocus.ItemType))
774 Type designerType = viewService.GetDesignerType(itemToFocus.ItemType);
775 return typeof(WorkflowViewElement).IsAssignableFrom(designerType);