1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 #pragma warning disable 618
7 namespace System.Activities.Presentation
9 using System.Activities.Presentation.Internal.PropertyEditing;
10 using System.Activities.Presentation.Model;
11 using System.Activities.Presentation.Services;
12 using System.Collections;
13 using System.Collections.Generic;
14 using System.Collections.Specialized;
15 using System.Diagnostics.CodeAnalysis;
16 using System.Globalization;
20 using System.Windows.Automation.Peers;
21 using System.Windows.Controls;
22 using System.Windows.Input;
23 using System.Windows.Markup;
24 using System.Windows.Media;
25 using System.Windows.Threading;
26 using System.Activities.Presentation.View;
27 using System.Windows.Shapes;
29 // This is similar to the WorkflowItemPresenter , but its an edit box for collections. It supports drag drop, and delete.
30 // it auto refreshes the collection on collection changed events.
31 public class WorkflowItemsPresenter : ContentControl, IMultipleDragEnabledCompositeView
34 public static readonly DependencyProperty HintTextProperty =
35 DependencyProperty.Register("HintText", typeof(string), typeof(WorkflowItemsPresenter), new UIPropertyMetadata(String.Empty, new PropertyChangedCallback(WorkflowItemsPresenter.OnHintTextChanged)));
37 public static readonly DependencyProperty ItemsProperty =
38 DependencyProperty.Register("Items", typeof(ModelItemCollection), typeof(WorkflowItemsPresenter), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(WorkflowItemsPresenter.OnItemsChanged)));
40 public static readonly DependencyProperty SpacerTemplateProperty =
41 DependencyProperty.Register("SpacerTemplate", typeof(DataTemplate), typeof(WorkflowItemsPresenter), new UIPropertyMetadata(null));
43 public static readonly DependencyProperty HeaderTemplateProperty =
44 DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(WorkflowItemsPresenter), new UIPropertyMetadata(null));
46 public static readonly DependencyProperty FooterTemplateProperty =
47 DependencyProperty.Register("FooterTemplate", typeof(DataTemplate), typeof(WorkflowItemsPresenter), new UIPropertyMetadata(null));
49 public static readonly DependencyProperty ItemsPanelProperty =
50 DependencyProperty.Register("ItemsPanel", typeof(ItemsPanelTemplate), typeof(WorkflowItemsPresenter), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(WorkflowItemsPresenter.OnItemsPanelChanged)));
52 public static readonly DependencyProperty IndexProperty =
53 DependencyProperty.RegisterAttached("Index", typeof(int), typeof(WorkflowItemsPresenter), new UIPropertyMetadata(addAtEndMarker));
55 public static readonly DependencyProperty AllowedItemTypeProperty =
56 DependencyProperty.Register("AllowedItemType", typeof(Type), typeof(WorkflowItemsPresenter), new UIPropertyMetadata(typeof(object)));
58 public static readonly DependencyProperty IsDefaultContainerProperty =
59 DependencyProperty.Register("IsDefaultContainer", typeof(bool), typeof(WorkflowItemsPresenter), new UIPropertyMetadata(false));
61 public static readonly DependencyProperty DroppingTypeResolvingOptionsProperty =
62 DependencyProperty.Register("DroppingTypeResolvingOptions", typeof(TypeResolvingOptions), typeof(WorkflowItemsPresenter));
65 const int addAtEndMarker = -2;
67 int selectedSpacerIndex;
72 EditingContext context = null;
73 bool isRegisteredWithParent = false;
74 bool populateOnLoad = false;
75 bool handleSpacerGotKeyboardFocus = false;
78 public WorkflowItemsPresenter()
80 panel = new ItemsControl();
81 panel.Focusable = false;
82 hintTextGrid = new Grid();
83 hintTextGrid.Focusable = false;
84 hintTextGrid.Background = Brushes.Transparent;
85 hintTextGrid.DataContext = this;
86 hintTextGrid.SetBinding(Grid.MinHeightProperty, "MinHeight");
87 hintTextGrid.SetBinding(Grid.MinWidthProperty, "MinWidth");
88 TextBlock text = new TextBlock();
89 text.Focusable = false;
90 text.SetBinding(TextBlock.TextProperty, "HintText");
91 text.HorizontalAlignment = HorizontalAlignment.Center;
92 text.VerticalAlignment = VerticalAlignment.Center;
93 text.DataContext = this;
94 text.Foreground = new SolidColorBrush(SystemColors.GrayTextColor);
95 text.FontStyle = FontStyles.Italic;
96 ((IAddChild)hintTextGrid).AddChild(text);
98 this.outerGrid = new Grid()
100 RowDefinitions = { new RowDefinition(), new RowDefinition() },
101 ColumnDefinitions = { new ColumnDefinition() }
103 Grid.SetRow(this.panel, 0);
104 Grid.SetColumn(this.panel, 0);
105 Grid.SetRow(this.hintTextGrid, 1);
106 Grid.SetColumn(this.hintTextGrid, 0);
107 this.outerGrid.Children.Add(panel);
108 this.outerGrid.Children.Add(hintTextGrid);
112 public Type AllowedItemType
114 get { return (Type)GetValue(AllowedItemTypeProperty); }
115 set { SetValue(AllowedItemTypeProperty, value); }
118 public string HintText
120 get { return (string)GetValue(HintTextProperty); }
121 set { SetValue(HintTextProperty, value); }
124 [Fx.Tag.KnownXamlExternal]
125 public DataTemplate SpacerTemplate
127 get { return (DataTemplate)GetValue(SpacerTemplateProperty); }
128 set { SetValue(SpacerTemplateProperty, value); }
131 [Fx.Tag.KnownXamlExternal]
132 public DataTemplate HeaderTemplate
134 get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
135 set { SetValue(HeaderTemplateProperty, value); }
138 [Fx.Tag.KnownXamlExternal]
139 public DataTemplate FooterTemplate
141 get { return (DataTemplate)GetValue(FooterTemplateProperty); }
142 set { SetValue(FooterTemplateProperty, value); }
145 [Fx.Tag.KnownXamlExternal]
146 public ItemsPanelTemplate ItemsPanel
148 get { return (ItemsPanelTemplate)GetValue(ItemsPanelProperty); }
149 set { SetValue(ItemsPanelProperty, value); }
152 [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.CollectionPropertiesShouldBeReadOnly,
153 Justification = "Setter is provided to enable setting this property in code.")]
154 [Fx.Tag.KnownXamlExternal]
155 public ModelItemCollection Items
157 get { return (ModelItemCollection)GetValue(ItemsProperty); }
158 set { SetValue(ItemsProperty, value); }
161 EditingContext Context
167 IModelTreeItem modelTreeItem = this.Items as IModelTreeItem;
168 if (modelTreeItem != null)
170 this.context = modelTreeItem.ModelTreeManager.Context;
177 public bool IsDefaultContainer
179 get { return (bool)GetValue(IsDefaultContainerProperty); }
180 set { SetValue(IsDefaultContainerProperty, value); }
183 [Fx.Tag.KnownXamlExternal]
184 public TypeResolvingOptions DroppingTypeResolvingOptions
186 get { return (TypeResolvingOptions)GetValue(DroppingTypeResolvingOptionsProperty); }
187 set { SetValue(DroppingTypeResolvingOptionsProperty, value); }
190 static void OnHintTextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
192 WorkflowItemsPresenter itemsPresenter = (WorkflowItemsPresenter)dependencyObject;
193 itemsPresenter.UpdateHintTextVisibility(e.NewValue as string);
196 static void OnItemsChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
198 WorkflowItemsPresenter itemsPresenter = (WorkflowItemsPresenter)dependencyObject;
199 itemsPresenter.OnItemsChanged((ModelItemCollection)e.OldValue, (ModelItemCollection)e.NewValue);
202 static void OnItemsPanelChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
204 WorkflowItemsPresenter itemsPresenter = (WorkflowItemsPresenter)dependencyObject;
205 itemsPresenter.panel.ItemsPanel = (ItemsPanelTemplate)e.NewValue;
208 void OnItemsChanged(ModelItemCollection oldItemsCollection, ModelItemCollection newItemsCollection)
210 if (oldItemsCollection != null)
212 oldItemsCollection.CollectionChanged -= this.OnCollectionChanged;
215 if (newItemsCollection != null)
217 newItemsCollection.CollectionChanged += this.OnCollectionChanged;
220 if (!isRegisteredWithParent)
222 CutCopyPasteHelper.RegisterWithParentViewElement(this);
223 isRegisteredWithParent = true;
225 populateOnLoad = false;
229 void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
231 // if this.Items is null, and we are getting a collection changed that
232 // means this event some how happened before this can get the unloaded event
233 // and unsubscribe from this event.
234 if (this.Items == null)
238 bool fullRepopulateNeeded = true;
240 // when one item is dropped into this items presenter focus on the new view element for it.
241 if (e.Action == NotifyCollectionChangedAction.Add
242 && e.NewItems != null
243 && e.NewItems.Count == 1)
245 // insert itemview and spacer
246 fullRepopulateNeeded = false;
247 int itemViewIndex = GetViewIndexForItem(e.NewStartingIndex);
248 VirtualizedContainerService containerService = this.Context.Services.GetService<VirtualizedContainerService>();
249 UIElement itemView = containerService.GetContainer((ModelItem)e.NewItems[0], this);
250 this.panel.Items.Insert(itemViewIndex, itemView as UIElement);
251 // index 2 + i*2 + 1 is spacer i+1
252 FrameworkElement spacer = CreateSpacer();
253 this.panel.Items.Insert(itemViewIndex + 1, spacer);
256 ModelItem insertedItem = (ModelItem)e.NewItems[0];
257 this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() =>
259 UIElement view = (UIElement)insertedItem.View;
262 Keyboard.Focus(view);
267 else if (e.Action == NotifyCollectionChangedAction.Remove)
269 if (e.OldItems != null && e.OldItems.Count == 1)
271 fullRepopulateNeeded = false;
272 int itemViewIndex = GetViewIndexForItem(e.OldStartingIndex);
273 this.panel.Items.RemoveAt(itemViewIndex);
275 this.panel.Items.RemoveAt(itemViewIndex);
278 if (this.Items.Count == 0)
280 fullRepopulateNeeded = true;
283 // deselect removed items
284 if (this.Context != null)
286 IList<ModelItem> selectedItems = this.Context.Items.GetValue<Selection>().SelectedObjects.ToList();
287 foreach (ModelItem selectedAndRemovedItem in selectedItems.Intersect(e.OldItems.Cast<ModelItem>()))
289 Selection.Toggle(this.Context, selectedAndRemovedItem);
293 if (this.Items.Count > 0)
295 this.hintTextGrid.Visibility = Visibility.Collapsed;
299 this.hintTextGrid.Visibility = Visibility.Visible;
302 if (fullRepopulateNeeded)
308 protected override void OnInitialized(EventArgs e)
310 base.OnInitialized(e);
311 this.AllowDrop = true;
312 this.Content = outerGrid;
313 if (this.ItemsPanel != null)
315 this.panel.ItemsPanel = this.ItemsPanel;
318 ICompositeViewEvents containerEvents = null;
319 bool isDefault = false;
321 this.Loaded += (s, eventArgs) =>
323 isDefault = this.IsDefaultContainer;
324 selectedSpacerIndex = addAtEndMarker;
325 DependencyObject parent = VisualTreeHelper.GetParent(this);
326 while (null != parent && !typeof(ICompositeViewEvents).IsAssignableFrom(parent.GetType()))
328 parent = VisualTreeHelper.GetParent(parent);
330 containerEvents = parent as ICompositeViewEvents;
331 if (null != containerEvents)
335 containerEvents.RegisterDefaultCompositeView(this);
339 containerEvents.RegisterCompositeView(this);
342 if (this.Items != null)
344 //UnRegistering because of 137896: Inside tab control multiple Loaded events happen without an Unloaded event.
345 this.Items.CollectionChanged -= new NotifyCollectionChangedEventHandler(OnCollectionChanged);
346 this.Items.CollectionChanged += new NotifyCollectionChangedEventHandler(OnCollectionChanged);
350 this.PopulateContent();
354 this.Unloaded += (s, eventArgs) =>
356 if (null != containerEvents)
360 containerEvents.UnregisterDefaultCompositeView(this);
364 containerEvents.UnregisterCompositeView(this);
368 if (this.Items != null)
370 this.Items.CollectionChanged -= new NotifyCollectionChangedEventHandler(OnCollectionChanged);
372 populateOnLoad = true;
376 void PopulateContent()
378 this.panel.Items.Clear();
380 if (this.Items != null)
383 // index 0 is header.
384 ContentControl header = new ContentControl();
385 header.Focusable = false;
386 header.ContentTemplate = this.HeaderTemplate;
387 header.SetValue(IndexProperty, 0);
388 header.Drop += new DragEventHandler(OnSpacerDrop);
389 this.panel.Items.Add(header);
391 // index 1 is first spacer
392 FrameworkElement startSpacer = CreateSpacer();
393 this.panel.Items.Add(startSpacer);
395 foreach (ModelItem item in this.Items)
397 // index 2 + i*2 is itemView i
398 VirtualizedContainerService containerService = this.Context.Services.GetService<VirtualizedContainerService>();
399 UIElement itemView = containerService.GetContainer(item, this);
400 this.panel.Items.Add(itemView as UIElement);
401 // index 2 + i*2 + 1 is spacer i+1
402 FrameworkElement spacer = CreateSpacer();
403 this.panel.Items.Add(spacer);
405 // index 2 + count*2 is footer
406 ContentControl footer = new ContentControl();
407 footer.ContentTemplate = this.FooterTemplate;
408 footer.Focusable = true;
409 footer.IsHitTestVisible = true;
410 footer.IsTabStop = true;
411 footer.SetValue(IndexProperty, addAtEndMarker);
412 footer.Drop += new DragEventHandler(OnSpacerDrop);
413 footer.LostFocus += new RoutedEventHandler(OnSpacerLostFocus);
414 footer.GotFocus += new RoutedEventHandler(OnSpacerGotFocus);
415 this.panel.Items.Add(footer);
416 footer.Focusable = false;
418 UpdateHintTextVisibility(HintText);
421 int GetViewIndexForItem(int itemIndex)
423 return 2 + itemIndex * 2;
426 int GetViewIndexForSpacer(int spacerIndex)
428 return 2 + spacerIndex * 2 + 1;
431 int GetSpacerIndex(int viewIndex)
439 return (viewIndex - 3) / 2 + 1;
443 void UpdateHintTextVisibility(string hintText)
445 if (this.hintTextGrid != null && this.Items != null)
447 this.hintTextGrid.Visibility = (this.Items.Count == 0 && !string.IsNullOrEmpty(hintText)) ? Visibility.Visible : Visibility.Collapsed;
451 private IList<object> GetOrderMetaData(List<ModelItem> items)
453 List<ModelItem> sortedList = this.SortSelectedItems(new List<ModelItem>(items));
454 this.CheckListConsistentAndThrow(items, sortedList);
455 return sortedList.Select((m) => m.GetCurrentValue()).ToList();
458 private FrameworkElement CreateSpacer()
460 FrameworkElement spacer = (this.SpacerTemplate != null) ? (FrameworkElement)this.SpacerTemplate.LoadContent() : new Rectangle();
461 spacer.IsHitTestVisible = true;
462 Control spacerControl = spacer as Control;
463 if (spacerControl != null)
465 spacerControl.IsTabStop = true;
467 spacer.Drop += new DragEventHandler(OnSpacerDrop);
468 spacer.LostFocus += new RoutedEventHandler(OnSpacerLostFocus);
469 spacer.GotFocus += new RoutedEventHandler(OnSpacerGotFocus);
470 spacer.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(OnSpacerGotKeyboardFocus);
471 spacer.MouseDown += new MouseButtonEventHandler(OnSpacerMouseDown);
475 void OnSpacerDrop(object sender, DragEventArgs e)
477 int index = GetSpacerIndexFromView(sender);
478 OnItemsDropped(e, index);
481 private int GetSpacerIndexFromView(object sender)
483 if (((DependencyObject)sender).ReadLocalValue(IndexProperty) != DependencyProperty.UnsetValue)
485 int index = (int)((DependencyObject)sender).GetValue(IndexProperty);
490 return GetSpacerIndex(this.panel.Items.IndexOf(sender));
494 void OnSpacerGotFocus(object sender, RoutedEventArgs e)
496 int index = GetSpacerIndexFromView(sender);
497 selectedSpacerIndex = index;
500 void OnSpacerGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
502 // Handle the event so that it won't be routed to the containing designer to affect selection
503 if (handleSpacerGotKeyboardFocus)
509 void OnSpacerLostFocus(object sender, RoutedEventArgs e)
511 int index = GetSpacerIndexFromView(sender);
512 selectedSpacerIndex = addAtEndMarker;
515 void OnSpacerMouseDown(object sender, MouseButtonEventArgs e)
517 // do not move focus if it's a ctrl right click.
518 if (e.RightButton == MouseButtonState.Pressed)
520 if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
526 // Schedule the Keyboard.Focus command to let it execute later than WorkflowViewElement.OnMouseDown
527 this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
529 this.handleSpacerGotKeyboardFocus = true;
530 Keyboard.Focus((FrameworkElement)sender);
531 this.handleSpacerGotKeyboardFocus = false;
535 private bool ShouldMoveItems(List<ModelItem> sortedModelItems, int index)
537 if (sortedModelItems.Count == 0)
542 // Should move if the items are not next to each other
543 if (!AreItemsConsecutive(sortedModelItems))
548 // Should not move if the new position is just before the first item or just after the last item or between them.
549 return index < this.Items.IndexOf(sortedModelItems[0]) || index > this.Items.IndexOf(sortedModelItems.Last()) + 1;
552 private bool AreItemsConsecutive(List<ModelItem> sortedModelItems)
554 Fx.Assert(sortedModelItems.Count > 0, "Should have at least one item.");
555 int oldIndex = this.Items.IndexOf(sortedModelItems[0]);
556 foreach (ModelItem item in sortedModelItems)
558 if (oldIndex != this.Items.IndexOf(item))
567 public List<ModelItem> SortSelectedItems(List<ModelItem> selectedItems)
569 if (selectedItems == null)
571 throw FxTrace.Exception.ArgumentNull("selectedItems");
573 if (selectedItems.Count < 2)
575 return selectedItems;
578 List<ModelItem> list = new List<ModelItem>();
579 // If the performance here is bad, we can use HashSet for selectedItems
581 foreach (ModelItem item in this.Items)
583 int index = selectedItems.IndexOf(item);
586 // use the reference in selectedItems.
587 list.Add(selectedItems[index]);
591 // in case passing some items that are not in
593 if (list.Count != selectedItems.Count)
595 // throw FxTrace.Exception.
596 throw FxTrace.Exception.AsError(new ArgumentException(SR.Error_CantFindItemInWIsP));
601 public void OnItemsMoved(List<ModelItem> movedItems)
603 if (movedItems == null)
605 throw FxTrace.Exception.ArgumentNull("movedItems");
608 DragDropHelper.ValidateItemsAreOnView(movedItems, this.Items);
609 this.OnItemsDelete(movedItems);
612 void OnItemsDropped(DragEventArgs e, int index)
614 ModelItemHelper.TryCreateImmediateEditingScopeAndExecute(this.Items.GetEditingContext(), System.Activities.Presentation.SR.CollectionAddEditingScopeDescription, (es) =>
616 DragDropHelper.SetDragDropCompletedEffects(e, DragDropEffects.None);
617 List<object> droppedObjects = new List<object>(DragDropHelper.GetDroppedObjects(this, e, Context));
618 List<WorkflowViewElement> movedViewElements = new List<WorkflowViewElement>();
620 List<object> externalMoveList = new List<object>();
621 List<ModelItem> internalMoveList = new List<ModelItem>();
623 // Step 1: Sort the list
624 List<object> sortedDroppingList = DragDropHelper.SortSelectedObjects(droppedObjects);
627 // Step 2: Categorize dropped objects by their source container.
628 foreach (object droppedObject in sortedDroppingList)
630 ModelItem modelItem = droppedObject as ModelItem;
631 WorkflowViewElement view = (modelItem == null) ? null : (modelItem.View as WorkflowViewElement);
634 externalMoveList.Add(droppedObject);
637 UIElement container = DragDropHelper.GetCompositeView(view);
638 if (container == this)
640 internalMoveList.Add(modelItem);
643 movedViewElements.Add(view);
644 externalMoveList.Add(droppedObject);
647 // Step 3: Internal movement
648 if (this.ShouldMoveItems(internalMoveList, index))
650 foreach (ModelItem modelItem in internalMoveList)
652 int oldIndex = this.Items.IndexOf(modelItem);
653 this.Items.Remove(modelItem);
655 //if element is placed ahead of old location, decrement the index not to include moved object
656 if (oldIndex < index)
658 this.InsertItem(index - 1, modelItem);
662 this.InsertItem(index, modelItem);
668 // Step 4: External move and drop from toolbox
669 foreach (object droppedObject in externalMoveList)
671 if (!this.IsDropAllowed(droppedObject))
675 this.InsertItem(index++, droppedObject);
676 DragDropHelper.SetDragDropCompletedEffects(e, DragDropEffects.Move);
678 DragDropHelper.SetDragDropMovedViewElements(e, movedViewElements);
687 private void CheckListConsistentAndThrow(List<ModelItem> src, List<ModelItem> copied)
689 bool valid = DragDropHelper.AreListsIdenticalExceptOrder(src, copied);
692 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Error_BadOutputFromSortSelectedItems));
696 private bool IsDropAllowed(object droppedObject)
698 bool isDropAllowed = false;
699 ModelItem modelItem = droppedObject as ModelItem;
700 if (modelItem != null && !IsInParentChain(modelItem))
702 if (this.AllowedItemType.IsAssignableFrom(modelItem.ItemType))
704 isDropAllowed = true;
707 else if (droppedObject is Type && this.AllowedItemType.IsAssignableFrom((Type)droppedObject))
709 isDropAllowed = true;
713 if (this.AllowedItemType.IsAssignableFrom(droppedObject.GetType()))
715 isDropAllowed = true;
718 return isDropAllowed;
721 private bool IsInParentChain(ModelItem droppedModelItem)
723 bool isInParentChain = false;
724 ModelItem parentModelItem = this.Items;
725 while (parentModelItem != null)
727 if (parentModelItem == droppedModelItem)
729 isInParentChain = true;
732 parentModelItem = parentModelItem.Parent;
734 return isInParentChain;
737 void InsertItem(int index, object droppedObject)
739 ModelItem insertedItem = null;
740 if (index == addAtEndMarker)
742 insertedItem = this.Items.Add(droppedObject);
746 insertedItem = this.Items.Insert(index, droppedObject);
748 if (insertedItem != null)
750 Selection.SelectOnly(this.Context, insertedItem);
754 protected override void OnDrop(DragEventArgs e)
756 int index = addAtEndMarker;
757 WorkflowViewElement dropTarget = null;
758 if (e.OriginalSource is WorkflowViewElement)
760 dropTarget = (WorkflowViewElement)e.OriginalSource;
764 dropTarget = VisualTreeUtils.FindFocusableParent<WorkflowViewElement>((UIElement)e.OriginalSource);
767 if (null != dropTarget && null != dropTarget.ModelItem)
769 int targetIndex = this.Items.IndexOf(dropTarget.ModelItem);
770 if (-1 != targetIndex)
772 index = targetIndex + 1;
775 OnItemsDropped(e, index);
779 void OnDrag(DragEventArgs e)
783 if (!DragDropHelper.AllowDrop(e.Data, this.Context, this.AllowedItemType))
785 e.Effects = DragDropEffects.None;
791 protected override void OnDragEnter(DragEventArgs e)
797 protected override void OnDragOver(DragEventArgs e)
804 public void OnItemMoved(ModelItem modelItem)
806 if (this.Items.Contains(modelItem))
808 this.Items.Remove(modelItem);
812 protected override AutomationPeer OnCreateAutomationPeer()
814 return new WorkflowItemsPresenterAutomationPeer(this);
817 public object OnItemsCut(List<ModelItem> itemsToCut)
819 List<object> orderMetaData = GetOrderMetaData(itemsToCut).ToList();
820 foreach (ModelItem item in itemsToCut)
822 this.Items.Remove(item);
823 this.Context.Items.SetValue(new Selection(new ArrayList()));
825 return orderMetaData;
828 public object OnItemsCopied(List<ModelItem> itemsToCopy)
830 return this.GetOrderMetaData(itemsToCopy);
833 public void OnItemsPasted(List<object> itemsToPaste, List<object> metaData, Point pastePoint, WorkflowViewElement pastePointReference)
835 // first see if a spacer is selected.
836 int index = this.selectedSpacerIndex;
837 // else see if we can paste after a selected child
840 Selection currentSelection = this.Context.Items.GetValue<Selection>();
841 index = this.Items.IndexOf(currentSelection.PrimarySelection);
842 //paste after the selected child
850 index = addAtEndMarker;
853 IList<object> mergedItemsToPaste = CutCopyPasteHelper.SortFromMetaData(itemsToPaste, metaData);
855 List<ModelItem> modelItemsToSelect = new List<ModelItem>();
857 foreach (object itemToPaste in mergedItemsToPaste)
859 if (IsDropAllowed(itemToPaste))
861 if (index == addAtEndMarker)
863 modelItemsToSelect.Add(this.Items.Add(itemToPaste));
867 modelItemsToSelect.Add(this.Items.Insert(index, itemToPaste));
876 this.Dispatcher.BeginInvoke(
879 this.Context.Items.SetValue(new Selection(modelItemsToSelect));
881 Windows.Threading.DispatcherPriority.ApplicationIdle,
885 public void OnItemsDelete(List<ModelItem> itemsToDelete)
887 if (null != itemsToDelete)
889 itemsToDelete.ForEach(p =>
891 if (null != this.Items && this.Items.Contains(p))
893 this.Items.Remove(p);
900 public bool CanPasteItems(List<object> itemsToPaste)
903 if (null != itemsToPaste && itemsToPaste.Count > 0)
905 result = itemsToPaste.All(p => this.IsDropAllowed(p));
910 class WorkflowItemsPresenterAutomationPeer : UIElementAutomationPeer
912 WorkflowItemsPresenter owner;
914 public WorkflowItemsPresenterAutomationPeer(WorkflowItemsPresenter owner)
920 protected override AutomationControlType GetAutomationControlTypeCore()
922 return AutomationControlType.Custom;
925 protected override string GetAutomationIdCore()
927 string automationId = base.GetAutomationIdCore();
928 if (string.IsNullOrEmpty(automationId))
930 automationId = base.GetNameCore();
931 if (string.IsNullOrEmpty(automationId))
933 automationId = this.owner.GetType().Name;
939 protected override string GetNameCore()
941 // Return an empty string if some activites are dropped on the presenter
942 if (owner.Items.Count > 0)
946 string name = base.GetNameCore();
947 if (string.IsNullOrEmpty(name))
949 name = this.owner.HintText;
954 protected override string GetClassNameCore()
956 return this.owner.GetType().Name;