1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 namespace System.Activities.Presentation.View
7 using System.Activities.Presentation.Model;
8 using System.Activities.Presentation.Services;
9 using System.Collections.Generic;
12 using System.Windows.Controls;
13 using System.Windows.Media;
15 internal static class ViewUtilities
17 const string ExpandViewStateKey = "IsExpanded";
18 internal static bool DoesParentAlwaysExpandChildren(ModelItem modelItem, EditingContext context)
20 return IsParentOfType(modelItem, typeof(IExpandChild), context);
23 internal static bool DoesParentAlwaysCollapseChildren(ModelItem modelItem, EditingContext context)
25 bool parentAlwaysCollapsesChild = false;
26 Type parentDesignerType = GetParentDesignerType(modelItem, context);
27 if (typeof(WorkflowViewElement).IsAssignableFrom(parentDesignerType))
29 ActivityDesignerOptionsAttribute options = WorkflowViewService.GetAttribute<ActivityDesignerOptionsAttribute>(parentDesignerType);
30 parentAlwaysCollapsesChild = (options != null && options.AlwaysCollapseChildren);
32 return parentAlwaysCollapsesChild;
35 // Determines whether a particular ModelItem's view will be visible for a given breadcrumb root.
36 //It depends on whether the intermediate designers are expanded or collapsed.
37 internal static bool IsViewVisible(ModelItem child, ModelItem root, EditingContext context)
41 return !IsDefaultDesigner(context, root);
44 if (child.Parent == null)
49 WorkflowViewService viewService = GetViewService(context);
50 ModelItem parent = ModelUtilities.ReverseFindFirst(child.Parent, (ModelItem current) =>
52 return object.Equals(current, root) ||
53 HasView(current, viewService, false) &&
54 (!IsViewExpanded(current, context) || IsDefaultDesigner(context, current));
57 return object.Equals(parent, root) && !IsDefaultDesigner(context, root);
60 private static bool IsDefaultDesigner(EditingContext context, ModelItem item)
62 WorkflowViewService viewService = GetViewService(context);
63 Type viewType = viewService.GetDesignerType(item.ItemType);
64 return viewType == typeof(ActivityDesigner);
67 private static bool HasView(ModelItem modelItem, WorkflowViewService viewService, bool allowDrillIn)
69 ActivityDesignerOptionsAttribute options = WorkflowViewService.GetAttribute<ActivityDesignerOptionsAttribute>(modelItem.ItemType);
70 Type viewType = viewService.GetDesignerType(modelItem.ItemType);
71 return typeof(WorkflowViewElement).IsAssignableFrom(viewType) && (!allowDrillIn || options == null || options.AllowDrillIn);
74 // Get the first parent ModelItem that has a view
75 internal static ModelItem GetParentModelItemWithView(ModelItem modelItem, EditingContext context, bool allowDrillIn)
77 if (modelItem == null || modelItem.Parent == null)
82 WorkflowViewService viewService = GetViewService(context);
84 return ModelUtilities.ReverseFindFirst(modelItem.Parent, (ModelItem current) =>
86 return HasView(current, viewService, allowDrillIn);
90 // Determine whether the view of a ModelItem is expanded without querying the view itself - the view may have not been constructed.
91 internal static bool IsViewExpanded(ModelItem modelItem, EditingContext context)
93 if (modelItem == null)
98 bool isDesignerExpanded = true;
99 bool isDesignerPinned = false;
100 object isExpandedViewState = GetViewStateService(context).RetrieveViewState(modelItem, ExpandViewStateKey);
101 object isPinnedViewState = GetViewStateService(context).RetrieveViewState(modelItem, WorkflowViewElement.PinnedViewStateKey);
102 if (isExpandedViewState != null)
104 isDesignerExpanded = (bool)isExpandedViewState;
106 if (isPinnedViewState != null)
108 isDesignerPinned = (bool)isPinnedViewState;
111 DesignerView designerView = context.Services.GetService<DesignerView>();
113 return ShouldShowExpanded(IsBreadcrumbRoot(modelItem, context), DoesParentAlwaysExpandChildren(modelItem, context),
114 DoesParentAlwaysCollapseChildren(modelItem, context), isDesignerExpanded, designerView.ShouldExpandAll, designerView.ShouldCollapseAll, isDesignerPinned);
117 internal static bool IsBreadcrumbRoot(ModelItem modelItem, EditingContext context)
119 DesignerView designerView = context.Services.GetService<DesignerView>();
120 return modelItem != null && modelItem.View != null && modelItem.View.Equals(designerView.RootDesigner);
123 internal static bool ShouldShowExpanded(
125 bool parentAlwaysExpandChildren,
126 bool parentAlwaysCollapseChildren,
132 //ShowExpanded based on ExpandAll, CollapseAll, PinState, ExpandState
133 bool showExpanded = ShouldShowExpanded(expandState, expandAll, collapseAll, pinState);
135 //return value based on the position of the element in the workflow tree.
136 return (isRootDesigner || parentAlwaysExpandChildren || (!parentAlwaysCollapseChildren && showExpanded));
139 internal static bool ShouldShowExpanded(bool isExpanded, bool shouldExpandAll, bool shouldCollapseAll, bool isPinned)
147 return !shouldCollapseAll && (shouldExpandAll || isExpanded);
151 static WorkflowViewService GetViewService(EditingContext context)
153 return context.Services.GetService<ViewService>() as WorkflowViewService;
156 static ViewStateService GetViewStateService(EditingContext context)
158 return context.Services.GetService<ViewStateService>();
161 //Checks to see if the immediate parent WorkflowViewElement is of type "parentType".
162 static bool IsParentOfType(ModelItem modelItem, Type parentType, EditingContext context)
164 Type parentDesignerType = GetParentDesignerType(modelItem, context);
165 return parentType.IsAssignableFrom(parentDesignerType);
168 static Type GetParentDesignerType(ModelItem modelItem, EditingContext context)
170 ModelItem parent = GetParentModelItemWithView(modelItem, context, false);
173 return GetViewService(context).GetDesignerType(parent.ItemType);
178 internal static void MeasureView(WorkflowViewElement view, bool measureAsCollapsed)
180 bool expandState = view.ExpandState;
181 bool pinState = view.PinState;
183 if (measureAsCollapsed)
185 view.ForceCollapse();
188 view.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
191 if (view.ExpandState != expandState)
193 view.ExpandState = expandState;
195 if (view.PinState != pinState)
197 view.PinState = pinState;
201 // the job of this method is to construct a DisplayName for ActivityBuilder
202 // This name will be shown in breadcrumb bar.
203 // if ActivityBuilder.Name = "workflowconsoleApp.Sequence1"
204 // we want DisplayName = "Sequence1"
205 internal static string GetActivityBuilderDisplayName(ModelItem modelItem)
207 Fx.Assert(modelItem != null, "modelItem != null");
208 ModelItem nameModelItem = modelItem.Properties["Name"].Value;
209 string name = (nameModelItem == null) ? null : (string)nameModelItem.GetCurrentValue();
211 if (string.IsNullOrEmpty(name))
216 string displayName = string.Empty;
217 int indexOfDot = name.LastIndexOf('.');
220 // if make sure there at least one character after .
221 if (indexOfDot < name.Length - 1)
223 displayName = name.Substring(indexOfDot + 1);
234 internal static GeneralTransform GetTransformToRoot(Visual visual)
236 Visual rootVisual = GetRootVisual(visual);
238 return (rootVisual != null) ? visual.TransformToAncestor(rootVisual) : null;
241 private static Visual GetRootVisual(Visual visual)
243 Fx.Assert(visual != null, "visual should not be null");
247 PresentationSource source = PresentationSource.FromDependencyObject(visual);
250 root = source.RootVisual;
253 // PresentationSource will be null if the element is not in a window
254 // Window w = new Window();
255 // Button b = new Button();
258 // PresentationSource.FromDependencyObject(b) will return an instance
260 // PresentationSource.FromDependencyObject(b) will return null
261 // The reason of tree walk is to make some effort to support
262 // the scenario where user wants to capture a visual that is
266 for (DependencyObject current = visual;
267 current != null; current = VisualTreeHelper.GetParent(current))
269 // Maybe Visual is not enought in some case, but I don't get a sample
270 // till now. If it happens, add LogicalTreeHelper.GetParent() to the
271 // parent getting chain.
272 Visual currentVisual = current as Visual;
273 if (currentVisual != null)
275 root = currentVisual;