1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 namespace System.Activities.Presentation
7 using System.Activities.Presentation.Hosting;
8 using System.Activities.Presentation.Internal.PropertyEditing;
9 using System.Activities.Presentation.Model;
10 using System.Activities.Presentation.Services;
11 using System.Activities.Presentation.View;
12 using System.Activities.Statements;
13 using System.Collections.Generic;
17 using System.Windows.Automation.Peers;
18 using System.Windows.Controls;
19 using System.Windows.Data;
20 using System.Windows.Input;
21 using System.Windows.Media;
22 using System.Windows.Shapes;
23 using System.Windows.Threading;
26 enum InsertionPosition
33 class AutoWrapEventArgs : EventArgs
35 public Activity ExistingActivity { get; set; }
36 public InsertionPosition InsertionPosition { get; set; }
37 public List<Activity> ActivitiesToBeInserted { get; set; }
40 // This class provides a visual edit box to edit ModelItems. Textbox offers to edit strings, ints as a TextBlock and a cursor visually,
41 // The workflowitempresenter edits modelitems by picking their view using the view service. It presents s the visual for the modelitem
42 // pointe by Item property if it is set, it shows the hint text if the property is not set. It allows the associated item to be deleted
43 // visually , and removes the reference to Item when deleted. It also allows droping ModelItems, to set the Item property to the dropped
45 public sealed class WorkflowItemPresenter : ContentControl, ICompositeView
47 public static readonly DependencyProperty HintTextProperty =
48 DependencyProperty.Register("HintText", typeof(string), typeof(WorkflowItemPresenter), new UIPropertyMetadata(String.Empty));
50 public static readonly DependencyProperty ItemProperty =
51 DependencyProperty.Register("Item", typeof(ModelItem), typeof(WorkflowItemPresenter), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(WorkflowItemPresenter.OnItemChanged)));
53 public static readonly DependencyProperty AllowedItemTypeProperty =
54 DependencyProperty.Register("AllowedItemType", typeof(Type), typeof(WorkflowItemPresenter), new UIPropertyMetadata(typeof(object)));
56 public static readonly DependencyProperty IsDefaultContainerProperty =
57 DependencyProperty.Register("IsDefaultContainer", typeof(bool), typeof(WorkflowItemPresenter), new UIPropertyMetadata(false));
59 public static readonly DependencyProperty DroppingTypeResolvingOptionsProperty =
60 DependencyProperty.Register("DroppingTypeResolvingOptions", typeof(TypeResolvingOptions), typeof(WorkflowItemPresenter));
62 SpacerHelper spacerHelper;
64 StackPanel stackPanel;
67 EditingContext context = null;
68 bool shouldSetFocus = false;
69 bool isItemPastedOrDropped = false;
71 public WorkflowItemPresenter()
73 this.text = new TextBlock();
74 this.text.SetBinding(TextBlock.TextProperty, "HintText");
75 this.text.DataContext = this;
76 this.text.HorizontalAlignment = HorizontalAlignment.Center;
77 this.text.VerticalAlignment = VerticalAlignment.Center;
78 this.text.Foreground = new SolidColorBrush(SystemColors.GrayTextColor);
79 this.text.FontStyle = FontStyles.Italic;
81 this.contentGrid = new Grid();
82 this.contentGrid.Background = Brushes.Transparent;
83 this.contentGrid.VerticalAlignment = VerticalAlignment.Center;
84 this.contentGrid.Children.Add(text);
86 this.stackPanel = new StackPanel();
87 this.stackPanel.HorizontalAlignment = HorizontalAlignment.Center;
88 this.stackPanel.VerticalAlignment = VerticalAlignment.Center;
89 this.stackPanel.Children.Add(contentGrid);
91 this.containerGrid = new Grid();
92 this.containerGrid.Children.Add(stackPanel);
93 this.containerGrid.Background = Brushes.Transparent;
96 internal bool AutoWrapInSequenceEnabled
100 // Don't allow auto wrap in sequence if allowed item isn't of type of Activity
101 return this.Context != null
102 && this.Context.Services.GetService<DesignerConfigurationService>().AutoSurroundWithSequenceEnabled
103 && typeof(Activity).IsAssignableFrom(this.AllowedItemType);
111 return this.Item == null ? null :
112 this.Item.GetCurrentValue() as Activity;
116 List<Activity> ObjectList2ActivityList(IEnumerable<object> droppedObjects)
118 List<Activity> activityList = new List<Activity>();
119 foreach (object droppedObject in droppedObjects)
121 object modelObject = droppedObject;
122 if (modelObject is ModelItem)
124 modelObject = ((ModelItem)droppedObject).GetCurrentValue();
126 if (modelObject is Activity)
128 activityList.Add(modelObject as Activity);
132 Fx.Assert("A non-activity is found in the list, there must be something seriously wrong!");
138 private List<WorkflowViewElement> ObjectList2WorkflowViewElementList(IEnumerable<object> droppedObjects)
140 List<WorkflowViewElement> movedViewElements = new List<WorkflowViewElement>();
141 foreach (object droppedObject in droppedObjects)
143 if (droppedObject is ModelItem && ((ModelItem)droppedObject).View != null)
145 WorkflowViewElement view = (WorkflowViewElement)((ModelItem)droppedObject).View;
146 WorkflowItemPresenter container = DragDropHelper.GetCompositeView(view) as WorkflowItemPresenter;
147 if (container != this)
149 movedViewElements.Add(view);
153 return movedViewElements;
156 // return true if really something is dropped, otherwise, false.
157 bool DoAutoWrapDrop(InsertionPosition insertionPos, IEnumerable<object> droppedObjects)
159 List<Activity> activityList = ObjectList2ActivityList(droppedObjects);
160 if (activityList.Count == 0)
165 AutoWrapEventArgs args = new AutoWrapEventArgs()
167 InsertionPosition = insertionPos,
168 ExistingActivity = this.MyActivity,
169 ActivitiesToBeInserted = activityList
172 using (ModelEditingScope scope = this.Context.Services.GetService<ModelService>().Root.BeginEdit(SR.WrapInSequenceDescription))
174 ModelItem sequenceActivity = WorkflowItemPresenter.AutoWrapInSequenceHandler(this.Context, args);
175 if (this.UpdateItem(sequenceActivity, true))
188 bool DoAutoWrapDrop(InsertionPosition insertionPos, DragEventArgs e, IList<object> droppedObjects = null)
190 if (droppedObjects == null)
192 ModelTreeManager manager = this.Context.Services.GetRequiredService<ModelTreeManager>();
193 EditingScope editingScope = null;
197 editingScope = ModelItemHelper.TryCreateImmediateEditingScope(manager, SR.WrapInSequenceDescription);
199 droppedObjects = this.GetSortedObjectList(e);
201 if (!this.DoAutoWrapDrop(insertionPos, droppedObjects))
206 if (editingScope != null)
208 editingScope.Complete();
213 if (editingScope != null)
215 editingScope.Dispose();
222 if (!this.DoAutoWrapDrop(insertionPos, droppedObjects))
228 if (!DragDropHelper.IsDraggingFromToolbox(e))
230 List<WorkflowViewElement> movedViewElements = ObjectList2WorkflowViewElementList(droppedObjects);
231 DragDropHelper.SetDragDropMovedViewElements(e, movedViewElements);
233 //Backward compatibility for 4.0
234 if (droppedObjects.Count == 1 && movedViewElements.Count == 1)
236 #pragma warning disable 618
237 DragDropHelper.SetDragDropCompletedEffects(e, DragDropEffects.Move);
238 #pragma warning restore 618
243 Fx.Assert(droppedObjects.Count == 1, "Dropping from Toolbox with count != 1");
245 // Set focus if it is dropping from ToolBox.
246 // In common drag/drop, the selection setting is done at the end of
248 if (this.Item == null)
253 Fx.Assert(typeof(Sequence).IsAssignableFrom(this.Item.ItemType),
254 "Auto Wrap didn't add a sequence. Is Item.Properties[\"Activities\"] still correct?");
255 foreach (ModelItem item in this.Item.Properties["Activities"].Collection)
257 // Find the ModelItem whose value is an activity from Toolbox.
258 if (item.GetCurrentValue() == droppedObjects[0])
260 this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() =>
272 protected override void OnInitialized(EventArgs e)
274 base.OnInitialized(e);
275 this.AllowDrop = true;
276 this.Content = containerGrid;
277 ICompositeViewEvents containerEvents = null;
278 bool isDefault = false;
280 this.Loaded += (s, eventArgs) =>
282 isDefault = this.IsDefaultContainer;
283 DependencyObject parent = VisualTreeHelper.GetParent(this);
284 while (null != parent && !typeof(ICompositeViewEvents).IsAssignableFrom(parent.GetType()))
286 parent = VisualTreeHelper.GetParent(parent);
288 containerEvents = parent as ICompositeViewEvents;
289 if (null != containerEvents)
293 containerEvents.RegisterDefaultCompositeView(this);
297 containerEvents.RegisterCompositeView(this);
300 this.shouldSetFocus = true;
302 if (this.AutoWrapInSequenceEnabled)
304 // spacer and placer holder
305 this.spacerHelper = new SpacerHelper(this);
309 this.Unloaded += (s, eventArgs) =>
311 if (null != containerEvents)
315 containerEvents.UnregisterDefaultCompositeView(this);
319 containerEvents.UnregisterCompositeView(this);
322 this.shouldSetFocus = false;
324 if (this.AutoWrapInSequenceEnabled)
326 if (this.spacerHelper != null)
328 this.spacerHelper.Unload();
329 this.spacerHelper = null;
335 public string HintText
337 get { return (string)GetValue(HintTextProperty); }
338 set { SetValue(HintTextProperty, value); }
341 [Fx.Tag.KnownXamlExternal]
342 public ModelItem Item
344 get { return (ModelItem)GetValue(ItemProperty); }
345 set { SetValue(ItemProperty, value); }
348 public Type AllowedItemType
350 get { return (Type)GetValue(AllowedItemTypeProperty); }
351 set { SetValue(AllowedItemTypeProperty, value); }
354 [Fx.Tag.KnownXamlExternal]
355 public TypeResolvingOptions DroppingTypeResolvingOptions
357 get { return (TypeResolvingOptions)GetValue(DroppingTypeResolvingOptionsProperty); }
358 set { SetValue(DroppingTypeResolvingOptionsProperty, value); }
361 EditingContext Context
367 IModelTreeItem modelTreeItem = this.Item as IModelTreeItem;
368 if (modelTreeItem != null)
370 this.context = modelTreeItem.ModelTreeManager.Context;
372 else // There is no ModelItem yet, try to walk up the tree to find a WorkflowViewElement.
374 WorkflowViewElement parentViewElement = GetParentWorkflowViewElement();
375 if (parentViewElement != null)
377 this.context = parentViewElement.Context;
386 public bool IsDefaultContainer
388 get { return (bool)GetValue(IsDefaultContainerProperty); }
389 set { SetValue(IsDefaultContainerProperty, value); }
392 protected override void OnRender(DrawingContext drawingContext)
394 CutCopyPasteHelper.RegisterWithParentViewElement(this);
395 base.OnRender(drawingContext);
398 private WorkflowViewElement GetParentWorkflowViewElement()
400 // Walk the logic tree first.
401 FrameworkElement parent = (FrameworkElement)this.Parent;
402 while (parent != null && !(parent is WorkflowViewElement))
404 parent = parent.Parent as FrameworkElement;
406 WorkflowViewElement result = parent as WorkflowViewElement;
407 // If not found, walk the visual tree.
410 parent = VisualTreeHelper.GetParent(this) as FrameworkElement;
411 while (parent != null && !(parent is WorkflowViewElement))
413 parent = VisualTreeHelper.GetParent(parent) as FrameworkElement;
415 result = parent as WorkflowViewElement;
421 static void OnItemChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
423 WorkflowItemPresenter control = (WorkflowItemPresenter)dependencyObject;
424 control.OnItemChanged(e);
427 void OnItemChanged(DependencyPropertyChangedEventArgs e)
429 object newItem = e.NewValue;
434 //We want to set the selection only if the item is dropped or pasted.
435 //We cannot set the selection in UpdateItem, since while pasting that would still be in EditingScope and this.Item will be null.
436 if (this.isItemPastedOrDropped)
438 Fx.Assert(this.Item != null, "Item cannot be null");
439 // If we are currently moving from somewhere else to a WorkflowItemPresenter, the currently
440 // focusing view element will be removed, we need to set the keyboard focus explicitly to
441 // avoid WPF FocusManager to focus on an element, leading to flashing effect.
442 Keyboard.Focus((UIElement)this.Item.View);
443 this.isItemPastedOrDropped = false;
445 if (this.shouldSetFocus)
447 this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() =>
449 // check for Item == null, we found an interesting bug, where the user
450 // could drop something in here, and undo the change before the code below
452 if (this.Item != null)
454 UIElement view = (UIElement)(this.Item.View);
457 Keyboard.Focus(view);
458 Selection.SelectOnly(this.Context, this.Item);
461 //this.shouldSetFocus = false;
467 // remove the selection if the previous value was selected.
468 if (this.Context != null)
470 if (this.Context.Items.GetValue<Selection>().SelectedObjects.Contains(e.OldValue))
472 this.Context.Items.SetValue(new Selection(new ModelItem[] { }));
479 void PopulateContent()
481 if (this.Item != null)
483 VirtualizedContainerService containerService = this.Context.Services.GetService<VirtualizedContainerService>();
484 UIElement itemView = containerService.GetContainer(this.Item, this);
485 this.contentGrid.Children.Clear();
486 this.contentGrid.Children.Add(itemView);
490 contentGrid.Children.Clear();
491 contentGrid.Children.Add(text);
495 bool UpdateItem(object newItem)
497 return UpdateItem(newItem, false);
500 bool UpdateItem(object newItem, bool allowReplaceExistingActivity)
502 bool updateSucceeded = false;
503 ModelItem newModelItem = newItem as ModelItem;
504 if (this.Item == null || allowReplaceExistingActivity)
506 if (newModelItem == null && newItem != null)
508 // try to wrap the droppedObject in a ModelItem.
509 ModelServiceImpl modelService = (ModelServiceImpl)this.Context.Services.GetService<ModelService>();
510 newModelItem = modelService.WrapAsModelItem(newItem);
512 if (this.CanUpdateItem(newModelItem))
514 // In order to allow for model updates that happens during the model item is drop, this is all done in an atomic unit.
515 using (ModelEditingScope editingScope = this.Context.Services.GetService<ModelService>().Root.BeginEdit(SR.PropertyChangeEditingScopeDescription))
517 this.Item = newModelItem;
518 editingScope.Complete();
520 updateSucceeded = true;
521 this.isItemPastedOrDropped = true;
524 return updateSucceeded;
528 bool CanUpdateItem(ModelItem newModelItem)
530 return null != newModelItem
531 && TypeUtilities.IsTypeCompatible(newModelItem.ItemType, this.AllowedItemType)
532 && !this.IsInParentChain(newModelItem);
535 List<object> GetSortedObjectList(DragEventArgs args)
537 IEnumerable<object> droppedObjects = DragDropHelper.GetDroppedObjects(this, args, this.context);
538 return DragDropHelper.SortSelectedObjects(droppedObjects);
541 bool DoSingleDrop(object droppedObject, DragEventArgs args)
543 if (UpdateItem(droppedObject))
546 #pragma warning disable 618
547 DragDropHelper.SetDragDropCompletedEffects(args, DragDropEffects.Move);
548 #pragma warning restore 618
549 if (droppedObject is ModelItem && ((ModelItem)droppedObject).View != null)
551 DragDropHelper.SetDragDropMovedViewElements(args, new WorkflowViewElement[] { ((ModelItem)droppedObject).View as WorkflowViewElement });
560 protected override void OnDrop(DragEventArgs e)
562 ModelTreeManager manager = this.Context.Services.GetService<ModelTreeManager>();
564 // When dragging from toolbox:
565 // editingScope should not be null
566 // there should only be one item
567 // When dragging from canvas:
568 // editingScope should be null
569 // Call editingScope.Complete() to commit changes, otherwise the editing scope will be aborted
570 using (EditingScope editingScope = ModelItemHelper.TryCreateImmediateEditingScope(manager, SR.PropertyChangeEditingScopeDescription))
572 List<object> droppedObjects = this.GetSortedObjectList(e);
573 #pragma warning disable 618
574 DragDropHelper.SetDragDropCompletedEffects(e, DragDropEffects.None);
575 #pragma warning restore 618
576 if (droppedObjects == null || droppedObjects.Count == 0)
580 if (droppedObjects.Count == 1)
582 if (this.DoSingleDrop(droppedObjects[0], e))
584 if (editingScope != null)
586 editingScope.Complete();
594 Fx.Assert(editingScope == null, "editingScope should be null for dragging from canvas.");
595 this.DoAutoWrapDrop(InsertionPosition.None, e, droppedObjects);
601 void OnDrag(DragEventArgs e)
605 this.UpdateEffects(e);
610 void UpdateEffects(DragEventArgs args)
612 if (!DragDropHelper.AllowDrop(args.Data, this.Context, this.AllowedItemType))
614 args.Effects = DragDropEffects.None;
618 protected override void OnDragEnter(DragEventArgs e)
624 protected override void OnDragOver(DragEventArgs e)
630 protected override void OnMouseDown(MouseButtonEventArgs e)
632 // do not move focus if it's a ctrl right click.
633 if (e.RightButton == MouseButtonState.Pressed)
635 if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
643 // Schedule the Keyboard.Focus command to let it execute later than WorkflowViewElement.OnMouseDown,
644 // where WorkflowViewElement will move the keyboard focus on itself
645 this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
647 Keyboard.Focus((FrameworkElement)this);
652 private bool IsInParentChain(ModelItem droppedModelItem)
654 bool isInParentChain = false;
655 // start with immediate workflowviewElement outside this.
656 WorkflowViewElement parentViewElement = GetParentWorkflowViewElement();
657 if (parentViewElement != null)
659 ModelItem parentModelItem = parentViewElement.ModelItem;
660 while (parentModelItem != null)
662 if (parentModelItem == droppedModelItem)
664 isInParentChain = true;
667 parentModelItem = parentModelItem.Parent;
670 return isInParentChain;
676 this.PopulateContent();
679 void ICompositeView.OnItemMoved(ModelItem modelItem)
681 if (this.Item == modelItem)
687 protected override AutomationPeer OnCreateAutomationPeer()
689 return new WorkflowItemPresenterAutomationPeer(this);
693 object ICompositeView.OnItemsCut(List<ModelItem> itemsToCut)
695 Fx.Assert(itemsToCut.Count == 1, "Only one item can be cut");
696 Fx.Assert(itemsToCut[0].Equals(this.Item), "Only one item can be cut.");
701 object ICompositeView.OnItemsCopied(List<ModelItem> itemsToCopy)
706 void ICompositeView.OnItemsPasted(List<object> itemsToPaste, List<object> metaData, Point pastePoint, WorkflowViewElement pastePointReference)
708 if (itemsToPaste.Count == 1)
711 UpdateItem(itemsToPaste[0]);
716 IList<object> sortedList = CutCopyPasteHelper.SortFromMetaData(itemsToPaste, metaData);
717 Fx.Assert(this.Item == null, "multi-paste on item != null is not supported now");
718 this.DoAutoWrapDrop(InsertionPosition.None, sortedList);
722 void ICompositeView.OnItemsDelete(List<ModelItem> itemsToDelete)
724 if (null != itemsToDelete && itemsToDelete.Contains(this.Item))
731 bool ICompositeView.CanPasteItems(List<object> itemsToPaste)
733 return null != itemsToPaste &&
734 itemsToPaste.Count > 0 &&
735 null != itemsToPaste[0] &&
737 ((itemsToPaste[0] is ModelItem && this.CanUpdateItem((ModelItem)itemsToPaste[0])) ||
738 (itemsToPaste[0] is Type && this.AllowedItemType.IsAssignableFrom((Type)itemsToPaste[0])) ||
739 this.AllowedItemType.IsAssignableFrom(itemsToPaste[0].GetType()));
743 class WorkflowItemPresenterAutomationPeer : UIElementAutomationPeer
745 WorkflowItemPresenter owner;
747 public WorkflowItemPresenterAutomationPeer(WorkflowItemPresenter owner)
753 protected override AutomationControlType GetAutomationControlTypeCore()
755 return AutomationControlType.Custom;
758 protected override string GetAutomationIdCore()
760 string baseAutomationID = base.GetAutomationIdCore();
761 if (!string.IsNullOrEmpty(baseAutomationID))
763 return baseAutomationID;
765 return this.owner.GetType().Name;
768 protected override string GetNameCore()
770 // Return an empty string if an activity is dropped on the presenter
771 if (owner.Item != null)
775 string name = base.GetNameCore();
776 if (string.IsNullOrEmpty(name))
778 name = this.owner.HintText;
783 protected override string GetClassNameCore()
785 return this.owner.GetType().Name;
789 private static ModelItem AutoWrapInSequenceHandler(EditingContext editingContext, AutoWrapEventArgs e)
791 Fx.Assert(e.ExistingActivity != null || e.InsertionPosition == InsertionPosition.None,
792 "Existing activity must not be null");
794 ModelItem sequence = editingContext.Services.GetService<ModelTreeManager>().CreateModelItem(null, new Sequence());
795 foreach (Activity activity in e.ActivitiesToBeInserted)
797 sequence.Properties["Activities"].Collection.Add(activity);
800 switch (e.InsertionPosition)
802 case InsertionPosition.Before:
803 sequence.Properties["Activities"].Collection.Add(e.ExistingActivity);
805 case InsertionPosition.After:
806 sequence.Properties["Activities"].Collection.Insert(0, e.ExistingActivity);
808 case InsertionPosition.None:
811 Fx.Assert("Invalid insert position");
818 // NOTE: This wrapper method is exclusively called by TransitionDesigner, because
819 // WIP of Transition.Action would handle the event if the dragged source comes from
820 // WIP of Transition.Trigger (see Bug 201342). However, Auto-Surround spacer is usually
821 // handled in DragEnter handler of WIP, and other ActivityDesigner should not need to
822 // access this method directly.
823 internal void ShowSpacerHelperOnDraggedItems(DragEventArgs arg)
825 this.spacerHelper.OnWfItemPresenterPreviewDragEnter(this, arg);
828 // classes and helpers for Spacer
829 private sealed class SpacerWrapper
831 public FrameworkElement Spacer { get; set; }
832 public SpacerPlaceholder Placeholder { get; set; }
834 public void ShowSpacer()
838 Spacer.Visibility = Visibility.Visible;
840 if (Placeholder != null)
842 Placeholder.Visibility = Visibility.Collapsed;
846 public void HideSpacer()
850 Spacer.Visibility = Visibility.Collapsed;
852 if (Placeholder != null)
854 Placeholder.Visibility = Visibility.Visible;
858 public bool HighlightPlaceholder
862 this.Placeholder.TargetVisiable = value;
867 // All the e.Handle = true in OnDragXXXEnter/Leave/Over:
868 // Prevent the events to be further handled by OnDrag, which will set DragDropEffects to None
869 private sealed class SpacerHelper
871 public SpacerWrapper TopSpacerWrapper { get; set; }
872 public SpacerWrapper BottomSpacerWrapper { get; set; }
873 public Timer SpacerTimer { get; set; }
875 private WorkflowItemPresenter wfItemPresenter;
876 private SpacerWrapper SpacerToShow { get; set; }
878 static private SpacerHelper uniqueSpacerHelper = null;
880 static private SpacerHelper UniqueSpacerHelper
884 if (uniqueSpacerHelper == value)
888 if (uniqueSpacerHelper != null)
890 uniqueSpacerHelper.HighLighted = false;
892 uniqueSpacerHelper = value;
893 if (uniqueSpacerHelper != null)
895 uniqueSpacerHelper.HighLighted = true;
900 public SpacerHelper(WorkflowItemPresenter wfItemPresenter)
902 Fx.Assert(wfItemPresenter != null, "null WorkflowItemPresenter");
903 this.TopSpacerWrapper = new SpacerWrapper();
904 this.BottomSpacerWrapper = new SpacerWrapper();
905 this.wfItemPresenter = wfItemPresenter;
909 public bool HighLighted
913 this.TopSpacerWrapper.HighlightPlaceholder = value;
914 this.BottomSpacerWrapper.HighlightPlaceholder = value;
921 this.wfItemPresenter.containerGrid.PreviewDrop -= new DragEventHandler(OnContainerGridPreviewDrop);
922 this.wfItemPresenter.PreviewDragEnter -= new DragEventHandler(OnWfItemPresenterPreviewDragEnter);
923 this.wfItemPresenter.PreviewDragLeave -= new DragEventHandler(OnWfItemPresenterPreviewDragLeave);
925 this.TopSpacerWrapper.Placeholder.DragEnter -= new DragEventHandler(OnTopPlaceholderDragEnter);
926 this.TopSpacerWrapper.Placeholder.DragLeave -= new DragEventHandler(OnPlaceHoderDragLeave);
927 this.TopSpacerWrapper.Spacer.DragEnter -= new DragEventHandler(OnTopSpacerDragEnter);
928 this.TopSpacerWrapper.Spacer.DragLeave -= new DragEventHandler(OnTopSpacerDragLeave);
930 this.BottomSpacerWrapper.Placeholder.DragEnter -= new DragEventHandler(OnBottomPlaceholderDragEnter);
931 this.BottomSpacerWrapper.Placeholder.DragLeave -= new DragEventHandler(OnPlaceHoderDragLeave);
932 this.BottomSpacerWrapper.Spacer.DragEnter -= new DragEventHandler(OnBottomSpacerDragEnter);
933 this.BottomSpacerWrapper.Spacer.DragLeave -= new DragEventHandler(OnBottomSpacerDragLeave);
935 this.SpacerTimer.Elapsed -= new ElapsedEventHandler(OnSpacerTimerElapsed);
938 void UpdateEffects(DragEventArgs args)
940 if (this.wfItemPresenter.Item == null)
942 // Item is null, then use WIP's UpdateEffects.
943 this.wfItemPresenter.UpdateEffects(args);
947 if (!this.AllowDropOnSpacer(args))
949 args.Effects = DragDropEffects.None;
953 void OnTopPlaceholderDragEnter(object sender, DragEventArgs e)
955 this.UpdateEffects(e);
956 this.OnPlaceholderEnter(this.TopSpacerWrapper, e);
960 void OnBottomPlaceholderDragEnter(object sender, DragEventArgs e)
962 this.UpdateEffects(e);
963 this.OnPlaceholderEnter(this.BottomSpacerWrapper, e);
967 void OnPlaceHoderDragLeave(object sender, DragEventArgs e)
969 this.UpdateEffects(e);
970 this.SpacerTimer.Stop();
974 void OnTopSpacerDragEnter(object sender, DragEventArgs e)
976 this.UpdateEffects(e);
977 this.TopSpacerWrapper.ShowSpacer();
981 void OnTopSpacerDragLeave(object sender, DragEventArgs e)
983 this.TopSpacerWrapper.HideSpacer();
987 void OnBottomSpacerDragEnter(object sender, DragEventArgs e)
989 this.BottomSpacerWrapper.ShowSpacer();
993 void OnBottomSpacerDragLeave(object sender, DragEventArgs e)
995 this.UpdateEffects(e);
996 this.BottomSpacerWrapper.HideSpacer();
1000 void OnSpacerOrPlaceholderDragOver(object sender, DragEventArgs e)
1002 this.UpdateEffects(e);
1006 void OnSpacerDrop(object sender, DragEventArgs e)
1008 if (!this.AllowDropOnSpacer(e))
1012 InsertionPosition insertionPos = (sender == this.BottomSpacerWrapper.Spacer)
1013 ? InsertionPosition.After : InsertionPosition.Before;
1015 ModelItemHelper.TryCreateImmediateEditingScopeAndExecute(this.wfItemPresenter.Context, SR.WrapInSequenceDescription, (es) =>
1017 if (this.wfItemPresenter.DoAutoWrapDrop(insertionPos, e))
1019 // auto wrap is successful
1022 // if we created an immedate editing scope, try to complete it.
1029 void OnPlaceholderDrop(object sender, DragEventArgs e)
1031 if (!this.AllowDropOnSpacer(e))
1035 InsertionPosition insertionPos = (sender == this.BottomSpacerWrapper.Placeholder)
1036 ? InsertionPosition.After : InsertionPosition.Before;
1037 ModelItemHelper.TryCreateImmediateEditingScopeAndExecute(this.wfItemPresenter.Context, SR.WrapInSequenceDescription, (es) =>
1039 if (this.wfItemPresenter.DoAutoWrapDrop(insertionPos, e))
1041 // auto wrap is successful
1044 // if we created an immediate editing scope, try to complete it.
1051 void OnSpacerTimerElapsed(object sender, ElapsedEventArgs e)
1053 this.wfItemPresenter.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
1055 if (this.SpacerToShow != null)
1057 SpacerToShow.ShowSpacer();
1058 SpacerToShow = null;
1063 void OnContainerGridPreviewDrop(object sender, DragEventArgs e)
1065 this.SpacerTimer.Stop();
1066 this.TopSpacerWrapper.HideSpacer();
1067 this.BottomSpacerWrapper.HideSpacer();
1068 UniqueSpacerHelper = null;
1071 private FrameworkElement CreateAndInitializeSpacer(VerticalAlignment alignment)
1073 FrameworkElement spacer = (SpacerTemplate != null)
1074 ? (FrameworkElement)SpacerTemplate.LoadContent()
1076 spacer.AllowDrop = true;
1077 spacer.DragOver += new DragEventHandler(OnSpacerOrPlaceholderDragOver);
1078 spacer.Drop += new DragEventHandler(OnSpacerDrop);
1079 spacer.VerticalAlignment = alignment;
1080 spacer.IsHitTestVisible = true;
1081 spacer.Visibility = Visibility.Collapsed;
1085 void OnWfItemPresenterPreviewDragLeave(object sender, DragEventArgs e)
1087 UniqueSpacerHelper = null;
1088 this.TopSpacerWrapper.HideSpacer();
1089 this.BottomSpacerWrapper.HideSpacer();
1092 // this method is made internal because WorkflowItemPresenter.ShowSpacerHelperOnDraggedItems
1093 // needs to access this method to show the spacer UI gesture for Auto-surround.
1094 internal void OnWfItemPresenterPreviewDragEnter(object sender, DragEventArgs arg)
1096 if (!this.AllowDropOnSpacer(arg))
1100 UniqueSpacerHelper = this;
1103 private void Loaded()
1105 this.TopSpacerWrapper.Spacer = CreateAndInitializeSpacer(VerticalAlignment.Bottom);
1106 this.TopSpacerWrapper.Placeholder = CreateSpacerPlaceHolder();
1107 this.BottomSpacerWrapper.Spacer = CreateAndInitializeSpacer(VerticalAlignment.Top);
1108 this.BottomSpacerWrapper.Placeholder = CreateSpacerPlaceHolder();
1111 this.SpacerTimer = new Timer(500);
1112 this.SpacerTimer.Elapsed += new ElapsedEventHandler(OnSpacerTimerElapsed);
1113 this.SpacerTimer.AutoReset = false;
1116 this.wfItemPresenter.stackPanel.Children.Insert(0, TopSpacerWrapper.Spacer);
1117 this.wfItemPresenter.stackPanel.Children.Insert(0, TopSpacerWrapper.Placeholder);
1118 this.wfItemPresenter.stackPanel.Children.Insert(this.wfItemPresenter.stackPanel.Children.Count, BottomSpacerWrapper.Spacer);
1119 this.wfItemPresenter.stackPanel.Children.Insert(this.wfItemPresenter.stackPanel.Children.Count, BottomSpacerWrapper.Placeholder);
1120 this.wfItemPresenter.containerGrid.Background = Brushes.Transparent;
1123 this.wfItemPresenter.containerGrid.PreviewDrop += new DragEventHandler(OnContainerGridPreviewDrop);
1124 this.wfItemPresenter.PreviewDragEnter += new DragEventHandler(OnWfItemPresenterPreviewDragEnter);
1125 this.wfItemPresenter.PreviewDragLeave += new DragEventHandler(OnWfItemPresenterPreviewDragLeave);
1126 this.TopSpacerWrapper.Placeholder.DragEnter += new DragEventHandler(OnTopPlaceholderDragEnter);
1127 this.TopSpacerWrapper.Placeholder.DragLeave += new DragEventHandler(OnPlaceHoderDragLeave);
1128 this.TopSpacerWrapper.Spacer.DragEnter += new DragEventHandler(OnTopSpacerDragEnter);
1129 this.TopSpacerWrapper.Spacer.DragLeave += new DragEventHandler(OnTopSpacerDragLeave);
1131 this.BottomSpacerWrapper.Placeholder.DragEnter += new DragEventHandler(OnBottomPlaceholderDragEnter);
1132 this.BottomSpacerWrapper.Placeholder.DragLeave += new DragEventHandler(OnPlaceHoderDragLeave);
1133 this.BottomSpacerWrapper.Spacer.DragEnter += new DragEventHandler(OnBottomSpacerDragEnter);
1134 this.BottomSpacerWrapper.Spacer.DragLeave += new DragEventHandler(OnBottomSpacerDragLeave);
1137 private static DataTemplate defaultSpacerTemplate = CreateDefaultSpacerTemplate();
1139 private static DataTemplate SpacerTemplate
1141 get { return defaultSpacerTemplate; }
1144 private static DataTemplate CreateDefaultSpacerTemplate()
1146 FrameworkElementFactory feFactory = new FrameworkElementFactory(typeof(VerticalConnector));
1147 DataTemplate dt = new DataTemplate() { VisualTree = feFactory };
1152 private SpacerPlaceholder CreateSpacerPlaceHolder()
1154 // The place holder should be something that can triger DragEnter
1155 SpacerPlaceholder spacerPlaceholder = new SpacerPlaceholder { MinHeight = 20, Visibility = Visibility.Visible, AllowDrop = true };
1156 spacerPlaceholder.DragOver += new DragEventHandler(OnSpacerOrPlaceholderDragOver);
1157 spacerPlaceholder.Drop += new DragEventHandler(OnPlaceholderDrop);
1158 return spacerPlaceholder;
1161 private void OnPlaceholderEnter(SpacerWrapper wrapper, DragEventArgs e)
1163 if (!this.AllowDropOnSpacer(e))
1167 this.SpacerToShow = wrapper;
1168 this.SpacerTimer.Start();
1172 private bool AllowDropOnSpacer(DragEventArgs e)
1174 return (this.wfItemPresenter.Item != null
1175 && !this.IsOwnerActivityBeingDragged(e)
1176 && DragDropHelper.AllowDrop(typeof(Sequence), this.wfItemPresenter.AllowedItemType) // Is Sequence allowed to be dropped inside the WIP? Beause it will trigger AutoWrap.
1177 && DragDropHelper.AllowDrop(e.Data, this.wfItemPresenter.Context, typeof(Activity))); // Is the item being dragged allowed to be dropped onto Sequence?
1180 private bool IsOwnerActivityBeingDragged(DragEventArgs e)
1182 if (this.wfItemPresenter.Item == null)
1188 // In case of a toolbox drop, DragDropHelper.GetObjectsToBeDropped
1189 // will create an instance, which will possibliy pop up a type picker
1190 // dialog for generic activities. So check for it first and avoid
1192 if (DragDropHelper.IsDraggingFromToolbox(e))
1196 IEnumerable<ModelItem> draggedObjects = DragDropHelper.GetDraggedModelItems(e);
1197 return draggedObjects.Contains(this.wfItemPresenter.Item);