1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 namespace System.Activities.Presentation
7 using System.Diagnostics;
9 using System.Windows.Documents;
10 using System.Windows.Media;
11 using System.Windows.Shapes;
12 using System.Activities.Presentation.Hosting;
13 using System.Activities.Presentation.Model;
14 using System.Activities.Presentation.View;
15 using System.Windows.Threading;
16 using System.Diagnostics.CodeAnalysis;
17 using System.Globalization;
18 using System.Activities.Presentation.Internal.PropertyEditing;
20 using System.Reflection;
21 using System.Activities.Presentation.Sqm;
22 using System.Collections.Generic;
23 using System.Windows.Controls;
25 using Microsoft.Activities.Presentation;
28 // This is a helper class for making dragdrop inside workflow designer easy. This abstracts out te encoding formats used in the
29 // DataObject that is passed on from Drag source to target.
30 public static class DragDropHelper
32 // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
33 public static readonly DependencyProperty DragSourceProperty =
34 DependencyProperty.RegisterAttached("DragSource", typeof(UIElement), typeof(DragDropHelper), new UIPropertyMetadata(null));
35 public static readonly string ModelItemDataFormat;
36 public static readonly string CompositeViewFormat;
37 public static readonly string CompletedEffectsFormat = "DragCompletedEffectsFormat";
38 public static readonly string WorkflowItemTypeNameFormat = "WorkflowItemTypeNameFormat";
39 public static readonly string DragAnchorPointFormat;
40 internal static readonly string ModelItemsDataFormat;
41 internal static readonly string MovedViewElementsFormat;
43 [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
44 static DragDropHelper()
46 string postfix = Guid.NewGuid().ToString();
47 //set per process unique data format names - this will disable possibility of trying to drag & drop operation
48 //between designers in two different VS instances (use Cut-Copy-Paste for that)
49 ModelItemDataFormat = string.Format(CultureInfo.InvariantCulture, "ModelItemFormat_{0}", postfix);
50 CompositeViewFormat = string.Format(CultureInfo.InvariantCulture, "CompositeViewFormat_{0}", postfix);
51 DragAnchorPointFormat = string.Format(CultureInfo.InvariantCulture, "DragAnchorFormat_{0}", postfix);
52 ModelItemsDataFormat = string.Format(CultureInfo.InvariantCulture, "ModelItemsFormat_{0}", postfix);
53 MovedViewElementsFormat = string.Format(CultureInfo.InvariantCulture, "MovedViewElementsFormat_{0}", postfix);
56 [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
57 public static void SetCompositeView(WorkflowViewElement workflowViewElement, UIElement dragSource)
59 if (workflowViewElement == null)
61 throw FxTrace.Exception.ArgumentNull("workflowViewElement");
63 if (dragSource == null)
65 throw FxTrace.Exception.ArgumentNull("dragSource");
67 workflowViewElement.SetValue(DragDropHelper.DragSourceProperty, dragSource);
70 [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
71 public static UIElement GetCompositeView(WorkflowViewElement workflowViewElement)
73 if (workflowViewElement == null)
75 throw FxTrace.Exception.ArgumentNull("workflowViewElement");
77 return (UIElement)workflowViewElement.GetValue(DragDropHelper.DragSourceProperty);
80 internal static DataObject DoDragMoveImpl(IEnumerable<WorkflowViewElement> draggedViewElements, Point referencePoint)
82 List<ModelItem> draggedModelItems = new List<ModelItem>();
84 WorkflowViewElement viewElement = null;
85 foreach (WorkflowViewElement view in draggedViewElements)
94 draggedModelItems.Add(view.ModelItem);
95 view.IsHitTestVisible = false;
98 DataObject dataObject = new DataObject(ModelItemsDataFormat, draggedModelItems);
101 if (viewElement != null)
103 dataObject.SetData(ModelItemDataFormat, viewElement.ModelItem);
104 dataObject.SetData(CompositeViewFormat, GetCompositeView(viewElement));
107 dataObject.SetData(DragAnchorPointFormat, referencePoint);
109 if (viewElement != null)
111 DesignerView designerView = viewElement.Context.Services.GetService<DesignerView>();
112 ViewElementDragShadow dragShadow = new ViewElementDragShadow(designerView.scrollableContent, draggedViewElements, referencePoint, designerView.ZoomFactor);
113 designerView.BeginDragShadowTracking(dragShadow);
114 //whenever drag drop fails - ensure getting rid of drag shadow
117 DragDrop.DoDragDrop(designerView, dataObject, DragDropEffects.Move | DragDropEffects.Copy | DragDropEffects.Scroll | DragDropEffects.Link);
121 //let the caller handle exception
126 designerView.EndDragShadowTracking(dragShadow);
127 foreach (WorkflowViewElement view in draggedViewElements)
131 view.IsHitTestVisible = true;
139 [Obsolete("This method does not support dragging multiple items. Use \"public static IEnumerable<WorkflowViewElement> DoDragMove(IEnumerable<WorkflowViewElement> draggedViewElements, Point referencePoint)\" instead.")]
140 public static DragDropEffects DoDragMove(WorkflowViewElement draggedViewElement, Point referencePoint)
142 if (draggedViewElement == null)
144 throw FxTrace.Exception.ArgumentNull("draggedViewElement");
146 if (referencePoint == null)
148 throw FxTrace.Exception.ArgumentNull("referencePoint");
150 ModelItem draggedActivityModelItem = draggedViewElement.ModelItem;
151 DataObject dataObject = new DataObject(ModelItemDataFormat, draggedActivityModelItem);
152 dataObject.SetData(CompositeViewFormat, GetCompositeView(draggedViewElement));
153 dataObject.SetData(DragAnchorPointFormat, referencePoint);
154 List<ModelItem> draggedModelItems = new List<ModelItem>();
155 draggedModelItems.Add(draggedActivityModelItem);
156 dataObject.SetData(ModelItemsDataFormat, draggedModelItems);
158 DesignerView view = draggedViewElement.Context.Services.GetService<DesignerView>();
159 ViewElementDragShadow dragShadow = new ViewElementDragShadow(view.scrollableContent, draggedViewElement, referencePoint, view.ZoomFactor);
161 draggedViewElement.IsHitTestVisible = false;
162 view.BeginDragShadowTracking(dragShadow);
164 //whenever drag drop fails - ensure getting rid of drag shadow
167 DragDrop.DoDragDrop(GetCompositeView(draggedViewElement), dataObject, DragDropEffects.Move | DragDropEffects.Copy | DragDropEffects.Scroll | DragDropEffects.Link);
171 //let the caller handle exception
176 view.EndDragShadowTracking(dragShadow);
177 draggedViewElement.IsHitTestVisible = true;
180 return GetDragDropCompletedEffects(dataObject);
183 public static bool AllowDrop(IDataObject draggedDataObject, EditingContext context, params Type[] allowedItemTypes)
186 if (draggedDataObject == null)
188 throw FxTrace.Exception.ArgumentNull("draggedDataObject");
192 throw FxTrace.Exception.ArgumentNull("context");
194 if (allowedItemTypes == null)
196 throw FxTrace.Exception.ArgumentNull("allowedItemTypes");
198 ReadOnlyState readOnlyState = context.Items.GetValue<ReadOnlyState>();
199 if (readOnlyState != null && readOnlyState.IsReadOnly)
203 if (!AllowDrop(draggedDataObject, context))
207 List<Type> draggedTypes = GetDraggedTypes(draggedDataObject);
208 return draggedTypes != null
209 && draggedTypes.Count != 0
210 && draggedTypes.All<Type>((p) =>
212 for (int i = 0; i < allowedItemTypes.Length; ++i)
214 if (allowedItemTypes[i] == null)
216 throw FxTrace.Exception.ArgumentNull(string.Format(CultureInfo.InvariantCulture, "allowedItemTypes[{0}]", i));
218 if (AllowDrop(p, allowedItemTypes[i]))
227 static bool AllowDrop(IDataObject draggedDataObject, EditingContext context)
229 ModelItem droppedModelItem = draggedDataObject.GetData(ModelItemDataFormat) as ModelItem;
230 if (droppedModelItem == null)
234 return ((IModelTreeItem)droppedModelItem).ModelTreeManager.Context.Equals(context);
237 internal static bool AllowDrop(Type draggedType, Type allowedItemType)
239 if (draggedType == null)
241 // This is the case where some external stuff (e.g. Recycle bin) get dragged over.
244 // This is a special case in GetDroppedObject() and replicated here.
245 // Check whether dragged type is IActivityTemplateFactory, if true, use Factory's implement type instead.
247 if (draggedType.TryGetActivityTemplateFactory(out factoryType))
249 draggedType = factoryType;
252 if (allowedItemType.IsAssignableFrom(draggedType))
256 else if (allowedItemType.IsGenericTypeDefinition && draggedType.IsGenericType)
258 // We don't have inheritance relationship for GenericTypeDefinition, therefore the right check is equality
259 return allowedItemType.Equals(draggedType.GetGenericTypeDefinition());
261 else if (allowedItemType.IsGenericType && draggedType.IsGenericTypeDefinition)
263 // Allow GenericTypeDefinition to be dropped with GenericType constraint, if user select a correct argument type, drop should work.
264 return draggedType.Equals(allowedItemType.GetGenericTypeDefinition());
266 else if (allowedItemType.IsGenericType && draggedType.IsGenericType && draggedType.ContainsGenericParameters)
268 // If the draggedType is generic type but it contains generic parameters, which may happen to match the constraint.
269 return allowedItemType.GetGenericTypeDefinition() == draggedType.GetGenericTypeDefinition();
277 internal static List<Type> GetDraggedTypes(IDataObject draggedDataObject)
279 List<Type> types = new List<Type>();
280 if (draggedDataObject != null)
282 if (draggedDataObject.GetDataPresent(ModelItemsDataFormat))
284 IEnumerable<ModelItem> modelItems = draggedDataObject.GetData(ModelItemsDataFormat) as IEnumerable<ModelItem>;
285 foreach (ModelItem modelItem in modelItems)
287 if (modelItem != null)
289 types.Add(modelItem.ItemType);
293 else if (draggedDataObject.GetDataPresent(ModelItemDataFormat))
295 ModelItem modelItem = draggedDataObject.GetData(ModelItemDataFormat) as ModelItem;
296 if (modelItem != null)
298 types.Add(modelItem.ItemType);
302 // This is an object dragged from somewhere else other than from within the designer surface
303 if (draggedDataObject.GetDataPresent(WorkflowItemTypeNameFormat))
305 // This is the case where the object is dropped from the toolbox
306 string text = draggedDataObject.GetData(WorkflowItemTypeNameFormat) as string;
307 if (!string.IsNullOrEmpty(text))
309 types.Add(Type.GetType(text));
317 internal static bool IsDraggingFromToolbox(DragEventArgs e)
319 return e.Data.GetDataPresent(WorkflowItemTypeNameFormat);
322 public static IEnumerable<object> GetDroppedObjects(DependencyObject dropTarget, DragEventArgs e, EditingContext context)
324 List<object> droppedObjects = new List<object>();
325 if (e.Data.GetDataPresent(ModelItemsDataFormat))
327 IEnumerable<ModelItem> droppedModelItems = e.Data.GetData(ModelItemsDataFormat) as IEnumerable<ModelItem>;
328 foreach (ModelItem modelItem in droppedModelItems)
330 droppedObjects.Add(modelItem);
335 object droppedObject = e.Data.GetData(ModelItemDataFormat) as ModelItem;
336 // could have been dropped from toolbox.
337 if (droppedObject == null)
340 if (e.Data.GetDataPresent(WorkflowItemTypeNameFormat))
342 string text = e.Data.GetData(WorkflowItemTypeNameFormat) as string;
343 if (!string.IsNullOrEmpty(text))
345 //try to use the text format to see if it holds a type name and try to create an object out of it.
346 type = Type.GetType(text);
349 droppedObject = GetDroppedObjectInstance(dropTarget, context, type, e.Data);
351 if (droppedObject != null)
353 droppedObjects.Add(droppedObject);
357 context.Services.GetService<DesignerPerfEventProvider>().WorkflowDesignerDrop();
359 Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,
362 context.Services.GetService<DesignerPerfEventProvider>().WorkflowDesignerIdleAfterDrop();
365 return droppedObjects;
368 internal static void ValidateItemsAreOnView(IList<ModelItem> items, ICollection<ModelItem> modelItemsOnView)
370 Fx.Assert(items != null, "items");
371 Fx.Assert(modelItemsOnView != null, "modelItemsOnView");
373 for (int index = 0; index < items.Count; ++index)
375 if (!modelItemsOnView.Contains(items[index]))
377 throw FxTrace.Exception.AsError(
378 new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Error_ItemNotOnView, index)));
383 [Obsolete("This method does not support dropping multiple items. Use \"public static IEnumerable<object> GetDroppedObjects(DependencyObject dropTarget, DragEventArgs e, EditingContext context)\" instead.")]
384 public static object GetDroppedObject(DependencyObject dropTarget, DragEventArgs e, EditingContext context)
386 IEnumerable<object> droppedObjects = GetDroppedObjects(dropTarget, e, context);
387 if (droppedObjects.Count() > 0)
389 return droppedObjects.First();
394 [SuppressMessage(FxCop.Category.Design, FxCop.Rule.DoNotCatchGeneralExceptionTypes,
395 Justification = "Any exception can be thrown from custom code. We don't want to crash VS.")]
396 [SuppressMessage("Reliability", "Reliability108",
397 Justification = "Any exception can be thrown from custom code. We don't want to crash VS.")]
398 internal static object GetDroppedObjectInstance(DependencyObject dropTarget, EditingContext context, Type type, IDataObject dataObject)
402 //check if type is generic
403 if (type.IsGenericTypeDefinition)
405 type = ResolveGenericParameters(dropTarget, context, type);
409 object droppedObject = null;
414 droppedObject = Activator.CreateInstance(type);
416 if (type.IsActivityTemplateFactory() && type.IsClass)
418 //find parent WorkflowViewElement - in case of mouse drop, current drop target most likely is ISourceContainer
419 if (!(dropTarget is WorkflowViewElement))
421 dropTarget = VisualTreeUtils.FindVisualAncestor<WorkflowViewElement>(dropTarget);
424 Type templateFactoryInterface2 = type.GetInterface(typeof(IActivityTemplateFactory<>).FullName);
425 if (templateFactoryInterface2 != null)
427 droppedObject = templateFactoryInterface2.InvokeMember("Create", BindingFlags.InvokeMethod, null, droppedObject, new object[] { dropTarget, dataObject }, CultureInfo.InvariantCulture);
429 else if (droppedObject is IActivityTemplateFactory)
431 droppedObject = ((IActivityTemplateFactory)droppedObject).Create(dropTarget);
436 // SQM: Log activity usage count
437 ActivityUsageCounter.ReportUsage(context.Services.GetService<IVSSqmService>(), type);
446 string details = ex.Message;
447 if (ex is TargetInvocationException && ex.InnerException != null)
449 details = ex.InnerException.Message;
453 ErrorReporting.ShowErrorMessage(string.Format(CultureInfo.CurrentUICulture, SR.CannotCreateInstance, TypeNameHelper.GetDisplayName(type, false)), details);
457 return droppedObject;
460 static Type ResolveGenericParameters(DependencyObject dropTarget, EditingContext context, Type type)
462 // look to see if there is a DefaultTypeArgumentAttribute on it
463 DefaultTypeArgumentAttribute typeArgumentAttribute = ExtensibilityAccessor.GetAttribute<DefaultTypeArgumentAttribute>(type);
464 if (typeArgumentAttribute != null && typeArgumentAttribute.Type != null)
466 type = type.MakeGenericType(typeArgumentAttribute.Type);
468 else //require user to resolve generic arguments
470 ActivityTypeResolver wnd = new ActivityTypeResolver();
473 WindowHelperService service = context.Services.GetService<WindowHelperService>();
476 service.TrySetWindowOwner(dropTarget, wnd);
480 TypeResolvingOptions dropTargetOptions = null;
481 TypeResolvingOptions activityTypeOptions = null;
483 //try to see if the container has any customization for type resolver
484 ICompositeView container = dropTarget as ICompositeView;
485 if (container != null)
487 dropTargetOptions = container.DroppingTypeResolvingOptions;
490 //try to see if the activity type in discourse has any customization for type resolver
491 TypeResolvingOptionsAttribute attr = WorkflowViewService.GetAttribute<TypeResolvingOptionsAttribute>(type);
494 activityTypeOptions = attr.TypeResolvingOptions;
496 //if both have type resolver, try to merge them
497 TypeResolvingOptions options = TypeResolvingOptions.Merge(dropTargetOptions, activityTypeOptions);
500 wnd.Options = options;
503 wnd.Context = context;
504 wnd.EditedType = type;
507 type = (true == wnd.ShowDialog() ? wnd.ConcreteType : null);
512 [Obsolete("This method does not support dragging multiple items. Use \"public static IEnumerable<ModelItem> GetDraggedModelItems(DragEventArgs e)\" instead.")]
513 public static ModelItem GetDraggedModelItem(DragEventArgs e)
515 return GetDraggedModelItemInternal(e);
518 internal static ModelItem GetDraggedModelItemInternal(DragEventArgs e)
520 IEnumerable<ModelItem> draggedModelItems = GetDraggedModelItems(e);
521 if (draggedModelItems.Count() > 0)
523 return draggedModelItems.First();
528 public static IEnumerable<ModelItem> GetDraggedModelItems(DragEventArgs e)
530 IEnumerable<ModelItem> draggedModelItems = e.Data.GetData(ModelItemsDataFormat) as IEnumerable<ModelItem>;
531 if (draggedModelItems != null)
533 return draggedModelItems;
537 ModelItem draggedItem = e.Data.GetData(ModelItemDataFormat) as ModelItem;
538 if (draggedItem != null)
540 return new ModelItem[] { draggedItem };
543 return new ModelItem[] { };
546 internal static bool AreListsIdenticalExceptOrder<T>(IList<T> sourceList, IList<T> destinationList)
549 // 1) introduce unseen object into the collection.
550 // 2) remove object from the collection.
551 // 3) introduce null in the collection.
553 if (sourceList == null)
555 return destinationList == null;
558 if (destinationList == null)
563 if (sourceList.Count != destinationList.Count)
567 HashSet<T> checkingMap = new HashSet<T>();
570 foreach (T item in sourceList)
572 bool ret = checkingMap.Add(item);
573 // an internal error, the item in src should be identical.
574 Fx.Assert(ret, "item in source list is not identical?");
577 foreach (T item in destinationList)
579 if (!checkingMap.Remove(item))
584 return checkingMap.Count == 0;
587 // 1) obj with CompositeView2: sort by IMultipleDragEnabledCompositeView SortSelectedItems.
588 // 2) obj with CompoisteView: no sort.
589 // 3) obj without CompositeView: just put them at the end of the list as the order in selectedObjects.
590 internal static List<object> SortSelectedObjects(IEnumerable<object> selectedObjects)
592 //1) Separate objects
593 Dictionary<ICompositeView, List<ModelItem>> viewItemListDictionary = new Dictionary<ICompositeView, List<ModelItem>>();
594 List<object> nonCompositeView = new List<object>();
595 List<object> retList = new List<object>();
596 foreach (object obj in selectedObjects)
598 ModelItem modelItem = obj as ModelItem;
599 if (modelItem == null || modelItem.View == null)
601 nonCompositeView.Add(obj);
604 ICompositeView container = DragDropHelper
605 .GetCompositeView(modelItem.View as WorkflowViewElement) as ICompositeView;
606 if (container == null)
608 nonCompositeView.Add(obj);
612 // add to dictionary.
613 if (!viewItemListDictionary.ContainsKey(container))
615 viewItemListDictionary.Add(container, new List<ModelItem>());
618 viewItemListDictionary[container].Add(modelItem);
621 // 2) sort when possible
622 foreach (KeyValuePair<ICompositeView, List<ModelItem>> pair in viewItemListDictionary)
624 IMultipleDragEnabledCompositeView view2 = pair.Key as IMultipleDragEnabledCompositeView;
625 List<ModelItem> sortedList = view2 == null ?
626 pair.Value : view2.SortSelectedItems(new List<ModelItem>(pair.Value));
627 if (!AreListsIdenticalExceptOrder(pair.Value, sortedList))
630 throw FxTrace.Exception.AsError(
631 new InvalidOperationException(SR.Error_BadOutputFromSortSelectedItems));
633 retList.AddRange(sortedList);
636 retList.AddRange(nonCompositeView);
640 [Obsolete("This method does not support dragging multiple items. Use \"public static UIElement GetCompositeView(WorkflowViewElement workflowViewElement)\" instead.")]
641 public static ICompositeView GetCompositeView(DragEventArgs e)
643 return (ICompositeView)e.Data.GetData(CompositeViewFormat);
646 public static Point GetDragDropAnchorPoint(DragEventArgs e)
648 Point referencePoint;
649 if (e.Data.GetDataPresent(DragAnchorPointFormat))
651 referencePoint = (Point)e.Data.GetData(DragAnchorPointFormat);
655 referencePoint = new Point(-1, -1);
657 return referencePoint;
660 [Obsolete("This method does not support dragging multiple items. Consider using \"public static void SetDragDropMovedViewElements(DragEventArgs e, IEnumerable<WorkflowViewElement> movedViewElements)\" instead.")]
661 public static void SetDragDropCompletedEffects(DragEventArgs e, DragDropEffects completedEffects)
665 e.Data.SetData(CompletedEffectsFormat, completedEffects);
667 catch (InvalidOperationException exception)
669 Trace.WriteLine(exception.ToString());
673 [Obsolete("This method does not support dragging multiple items. Consider using \"public static IEnumerable<WorkflowViewElement> GetDragDropMovedViewElements(DataObject data)\" instead.")]
674 public static DragDropEffects GetDragDropCompletedEffects(DataObject data)
678 throw FxTrace.Exception.ArgumentNull("data");
680 DragDropEffects completedEffects = DragDropEffects.None;
681 if (data.GetDataPresent(CompletedEffectsFormat))
683 completedEffects = (DragDropEffects)data.GetData(CompletedEffectsFormat);
685 return completedEffects;
688 internal static void SetDragDropMovedViewElements(DragEventArgs e, IEnumerable<WorkflowViewElement> movedViewElements)
692 throw FxTrace.Exception.ArgumentNull("e");
695 if (movedViewElements == null)
697 throw FxTrace.Exception.ArgumentNull("movedViewElements");
702 e.Data.SetData(MovedViewElementsFormat, movedViewElements);
704 catch (InvalidOperationException exception)
706 Trace.WriteLine(exception.ToString());
710 internal static IEnumerable<WorkflowViewElement> GetDragDropMovedViewElements(DataObject data)
714 throw FxTrace.Exception.ArgumentNull("data");
717 if (data.GetDataPresent(MovedViewElementsFormat))
719 return (IEnumerable<WorkflowViewElement>)data.GetData(MovedViewElementsFormat);
724 internal static int GetDraggedObjectCount(DragEventArgs e)
726 return GetDraggedTypes(e.Data).Count;
729 internal static Dictionary<WorkflowViewElement, Point> GetViewElementRelativeLocations(IEnumerable<WorkflowViewElement> viewElements)
731 DesignerView designerView = null;
732 Dictionary<WorkflowViewElement, Point> locations = new Dictionary<WorkflowViewElement, Point>();
733 Point topLeftPoint = new Point(double.PositiveInfinity, double.PositiveInfinity);
734 foreach (WorkflowViewElement viewElement in viewElements)
736 if (designerView == null)
738 designerView = viewElement.Context.Services.GetService<DesignerView>();
741 Point location = new Point(0, 0);
742 if (designerView.scrollableContent.IsAncestorOf(viewElement))
744 GeneralTransform transform = viewElement.TransformToAncestor(designerView.scrollableContent);
745 location = transform.Transform(new Point(0, 0));
748 if (location.X < topLeftPoint.X)
750 topLeftPoint.X = location.X;
753 if (location.Y < topLeftPoint.Y)
755 topLeftPoint.Y = location.Y;
758 locations.Add(viewElement, location);
761 foreach (WorkflowViewElement viewElement in viewElements)
763 locations[viewElement] = Vector.Add(new Vector(-topLeftPoint.X, -topLeftPoint.Y), locations[viewElement]);
768 internal static Dictionary<WorkflowViewElement, Point> GetDraggedViewElementRelativeLocations(DragEventArgs e)
770 List<WorkflowViewElement> draggedViewElements = new List<WorkflowViewElement>();
771 if (e.Data.GetDataPresent(ModelItemsDataFormat))
773 IEnumerable<ModelItem> draggedModelItems = e.Data.GetData(ModelItemsDataFormat) as IEnumerable<ModelItem>;
774 if (draggedModelItems != null)
776 foreach (ModelItem draggedModelItem in draggedModelItems)
778 if (draggedModelItem != null && draggedModelItem.View != null)
780 draggedViewElements.Add((WorkflowViewElement)draggedModelItem.View);
785 else if (e.Data.GetDataPresent(ModelItemDataFormat))
787 ModelItem draggedModelItem = e.Data.GetData(ModelItemDataFormat) as ModelItem;
788 if (draggedModelItem != null && draggedModelItem.View != null)
790 draggedViewElements.Add((WorkflowViewElement)draggedModelItem.View);
793 return GetViewElementRelativeLocations(draggedViewElements);
796 // Get rid of descendant model items when both ancestor and descendant and ancestor model items are selected
797 internal static IEnumerable<ModelItem> GetModelItemsToDrag(IEnumerable<ModelItem> modelItems)
799 HashSet<ModelItem> modelItemsToDrag = new HashSet<ModelItem>();
800 foreach (ModelItem modelItem in modelItems)
802 HashSet<ModelItem> parentModelItems = CutCopyPasteHelper.GetSelectableParentModelItems(modelItem);
803 parentModelItems.IntersectWith(modelItems);
804 if (parentModelItems.Count == 0)
806 modelItemsToDrag.Add(modelItem);
809 return modelItemsToDrag;
813 internal sealed class ViewElementDragShadow : Adorner
825 public ViewElementDragShadow(UIElement owner, WorkflowViewElement viewElement, Point offset, double scaleFactor)
828 Rect bounds = VisualTreeHelper.GetDescendantBounds(viewElement);
829 this.width = bounds.Width;
830 this.height = bounds.Height;
832 this.content = new Rectangle()
835 Height = this.height,
836 Fill = new VisualBrush(viewElement)
841 this.InitializeCommon(offset, scaleFactor);
844 public ViewElementDragShadow(UIElement owner, IEnumerable<WorkflowViewElement> viewElements, Point offset, double scaleFactor)
847 Dictionary<WorkflowViewElement, Point> locations = DragDropHelper.GetViewElementRelativeLocations(viewElements);
849 Grid grid = new Grid();
850 foreach (WorkflowViewElement viewElement in viewElements)
852 Rect bounds = VisualTreeHelper.GetDescendantBounds(viewElement);
853 Rectangle rectangle = new Rectangle()
855 Width = bounds.Width,
856 Height = bounds.Height,
857 Fill = new VisualBrush(viewElement),
858 Margin = new Thickness(locations[viewElement].X, locations[viewElement].Y, 0, 0),
859 VerticalAlignment = VerticalAlignment.Top,
860 HorizontalAlignment = HorizontalAlignment.Left
862 grid.Children.Add(rectangle);
864 grid.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
865 this.width = grid.DesiredSize.Width;
866 this.height = grid.DesiredSize.Height;
868 this.content = new Rectangle()
871 Height = this.height,
872 Fill = new VisualBrush(grid)
877 this.InitializeCommon(offset, scaleFactor);
880 internal void UpdatePosition(double x, double y)
882 if (this.Visibility == Visibility.Hidden)
884 this.Visibility = Visibility.Visible;
886 double oldX = this.x;
887 double oldY = this.y;
888 this.x = x - this.offsetX;
889 this.y = y - this.offsetY;
890 if (oldX != this.x || oldY != this.y)
892 this.layer = this.Parent as AdornerLayer;
893 this.layer.Update(this.AdornedElement);
897 public override GeneralTransform GetDesiredTransform(GeneralTransform transform)
899 GeneralTransformGroup result = new GeneralTransformGroup();
900 result.Children.Add(new TranslateTransform(this.x, this.y));
901 result.Children.Add(new ScaleTransform(this.scaleFactor, this.scaleFactor, this.x, this.y));
905 protected override Visual GetVisualChild(int index)
910 protected override int VisualChildrenCount
915 protected override Size ArrangeOverride(Size finalSize)
917 this.content.Arrange(new Rect(this.content.DesiredSize));
918 System.Diagnostics.Debug.WriteLine("DragShadow.ArrangeOverride " + this.content.DesiredSize);
919 return this.content.DesiredSize;
922 protected override Size MeasureOverride(Size constraint)
924 this.content.Measure(constraint);
925 System.Diagnostics.Debug.WriteLine("DragShadow.MeasureOverride " + this.content.DesiredSize);
926 return this.content.DesiredSize;
929 private void InitializeCommon(Point offset, double scaleFactor)
931 this.offsetX = offset.X * scaleFactor;
932 this.offsetY = offset.Y * scaleFactor;
933 this.Visibility = Visibility.Hidden;
934 this.scaleFactor = scaleFactor;