1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 namespace System.Activities.Presentation
8 using System.Activities.Debugger;
9 using System.Activities.Presentation.Hosting;
10 using System.Activities.Presentation.Model;
11 using System.Activities.Presentation.View;
12 using System.Activities.Presentation.Xaml;
13 using System.Activities.Statements;
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Diagnostics.CodeAnalysis;
17 using System.Globalization;
21 using System.Runtime.InteropServices;
22 using System.Runtime.Versioning;
23 using System.ServiceModel.Activities;
25 using System.Windows.Documents;
26 using System.Windows.Input;
27 using System.Windows.Media;
29 using Microsoft.Activities.Presentation;
30 using Microsoft.Activities.Presentation.Xaml;
32 public static class CutCopyPasteHelper
34 internal static readonly DependencyProperty ChildContainersProperty =
35 DependencyProperty.RegisterAttached("ChildContainers", typeof(HashSet<ICompositeView>), typeof(CutCopyPasteHelper), new UIPropertyMetadata(null));
37 static object workflowCallbackContext = null;
39 internal const string WorkflowClipboardFormat = "WorkflowXamlFormat";
40 internal const string WorkflowClipboardFormat_TargetFramework = "WorkflowXamlFormat_TargetFramework";
42 //define a workflow callback clipboard format - make it unique across all processes
43 static readonly string WorkflowCallbackClipboardFormat = string.Format(CultureInfo.InvariantCulture, "WorkflowCallbackFormat{0}", Guid.NewGuid());
45 const string versionInfo = "1.0";
47 static IList<Type> disallowedTypesForCopy;
49 static IEnumerable<Type> DisallowedTypesForCopy
53 if (null == disallowedTypesForCopy)
55 disallowedTypesForCopy = new List<Type>();
56 disallowedTypesForCopy.Add(typeof(ActivityBuilder));
57 disallowedTypesForCopy.Add(typeof(ModelItemKeyValuePair<,>));
58 disallowedTypesForCopy.Add(typeof(WorkflowService));
59 disallowedTypesForCopy.Add(typeof(Catch));
61 return disallowedTypesForCopy;
65 internal static void AddDisallowedTypeForCopy(Type type)
67 if (!DisallowedTypesForCopy.Any(p => type == p))
69 disallowedTypesForCopy.Add(type);
73 [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
74 static void AddChildContainer(WorkflowViewElement viewElement, ICompositeView sourceContainer)
76 if (viewElement == null)
78 throw FxTrace.Exception.AsError(new ArgumentNullException("viewElement"));
80 if (sourceContainer == null)
82 throw FxTrace.Exception.AsError(new ArgumentNullException("sourceContainer"));
85 HashSet<ICompositeView> containers = (HashSet<ICompositeView>)viewElement.GetValue(CutCopyPasteHelper.ChildContainersProperty);
86 if (containers == null)
88 containers = new HashSet<ICompositeView>();
89 viewElement.SetValue(CutCopyPasteHelper.ChildContainersProperty, containers);
91 containers.Add(sourceContainer);
94 [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
95 static HashSet<ICompositeView> GetChildContainers(WorkflowViewElement workflowViewElement)
97 HashSet<ICompositeView> childContainers = null;
98 if (workflowViewElement != null && workflowViewElement.ShowExpanded)
100 childContainers = (HashSet<ICompositeView>)workflowViewElement.GetValue(CutCopyPasteHelper.ChildContainersProperty);
102 return childContainers;
105 //This enables us to get children ICompositeViews from WorkflowViewElements.
106 //Eg. get the WorkflowItemsPresenter from SequenceDesigner.
107 //This is useful for Cut-Copy-Paste, Delete handling, etc.
108 internal static void RegisterWithParentViewElement(ICompositeView container)
110 WorkflowViewElement parent = GetParentViewElement(container);
113 CutCopyPasteHelper.AddChildContainer(parent, container);
117 //Returns the first WorkflowViewElement in the parent chain.
118 //If ICompositeView is a WorkflowViewElement this method returns the same object.
119 static WorkflowViewElement GetParentViewElement(ICompositeView container)
121 DependencyObject parent = container as DependencyObject;
122 return GetParentViewElement(parent);
125 //Returns the first WorkflowViewElement in the parent chain.
126 //Move this to a helper class.
127 internal static WorkflowViewElement GetParentViewElement(DependencyObject obj)
129 while (obj != null && !(obj is WorkflowViewElement))
131 obj = VisualTreeHelper.GetParent(obj);
133 return obj as WorkflowViewElement;
136 internal static IList<object> SortFromMetaData(IList<object> itemsToPaste, List<object> metaData)
138 IList<object> mergedItemsToPaste = SortFromMetaDataOnly(metaData);
139 // append items that are not sorted
140 foreach (object itemToPaste in itemsToPaste)
142 if (!mergedItemsToPaste.Contains(itemToPaste))
144 mergedItemsToPaste.Add(itemToPaste);
147 return mergedItemsToPaste;
150 internal static IList<object> SortFromMetaDataOnly(List<object> metaData)
152 List<object> mergedItemsToPaste = new List<object>();
153 if (metaData == null)
155 return mergedItemsToPaste;
158 foreach (object metaDataObject in metaData)
160 List<object> orderedItemsMetaData = metaDataObject as List<object>;
162 if (orderedItemsMetaData == null)
167 foreach (object objectToPaste in orderedItemsMetaData)
169 if (!mergedItemsToPaste.Contains(objectToPaste))
171 mergedItemsToPaste.Add(objectToPaste);
176 return mergedItemsToPaste;
179 public static void DoCut(EditingContext context)
183 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
185 Selection currentSelection = context.Items.GetValue<Selection>();
186 List<ModelItem> modelItemsToCut = new List<ModelItem>(currentSelection.SelectedObjects);
187 CutCopyPasteHelper.DoCut(modelItemsToCut, context);
190 internal static void DoCut(List<ModelItem> modelItemsToCut, EditingContext context)
192 if (modelItemsToCut == null)
194 throw FxTrace.Exception.AsError(new ArgumentNullException("modelItemsToCut"));
198 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
200 modelItemsToCut.RemoveAll((modelItem) => { return modelItem == null; });
201 if (modelItemsToCut.Count > 0)
203 using (EditingScope es = (EditingScope)modelItemsToCut[0].BeginEdit(SR.CutOperationEditingScopeDescription))
207 CutCopyOperation(modelItemsToCut, context, true);
209 catch (ExternalException e)
212 ErrorReporting.ShowErrorMessage(e.Message);
215 DesignerView view = context.Services.GetService<DesignerView>();
216 //Setting the selection to Breadcrumb root.
217 Fx.Assert(view != null, "DesignerView Cannot be null during cut");
218 WorkflowViewElement rootView = view.RootDesigner as WorkflowViewElement;
219 if (rootView != null)
221 Selection.SelectOnly(context, rootView.ModelItem);
228 public static void DoCopy(EditingContext context)
232 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
235 Selection currentSelection = context.Items.GetValue<Selection>();
236 List<ModelItem> modelItemsToCopy = new List<ModelItem>(currentSelection.SelectedObjects);
237 CutCopyPasteHelper.DoCopy(modelItemsToCopy, context);
240 private static void DoCopy(List<ModelItem> modelItemsToCopy, EditingContext context)
242 if (modelItemsToCopy == null)
244 throw FxTrace.Exception.AsError(new ArgumentNullException("modelItemsToCopy"));
249 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
252 // copy only works if we have DesignerView up and running so check and throw here
253 if (context.Services.GetService<DesignerView>() == null)
255 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CutCopyRequiresDesignerView));
257 modelItemsToCopy.RemoveAll((modelItem) => { return modelItem == null; });
260 CutCopyOperation(modelItemsToCopy, context, false);
262 catch (ExternalException e)
264 ErrorReporting.ShowErrorMessage(e.Message);
268 static void CutCopyOperation(List<ModelItem> modelItemsToCutCopy, EditingContext context, bool isCutOperation)
270 List<object> objectsOnClipboard = null;
271 List<object> metaData = null;
272 if (modelItemsToCutCopy.Count > 0)
274 objectsOnClipboard = new List<object>(modelItemsToCutCopy.Count);
275 metaData = new List<object>();
276 Dictionary<ICompositeView, List<ModelItem>> notifyDictionary = new Dictionary<ICompositeView, List<ModelItem>>();
277 UIElement breadCrumbRootView = ((DesignerView)context.Services.GetService<DesignerView>()).RootDesigner;
278 foreach (ModelItem modelItem in modelItemsToCutCopy)
280 object currentElement = modelItem.GetCurrentValue();
282 if (typeof(Activity).IsAssignableFrom(currentElement.GetType()))
285 if (AttachablePropertyServices.TryGetProperty(currentElement, XamlDebuggerXmlReader.FileNameName, out fileName))
287 AttachablePropertyServices.RemoveProperty(currentElement, XamlDebuggerXmlReader.FileNameName);
291 if (modelItem.View != null)
293 //The case where the breadcrumbroot designer is Cut/Copied. We do not delete the root designer, we only copy it.
294 if (breadCrumbRootView.Equals(modelItem.View))
296 notifyDictionary.Clear();
297 objectsOnClipboard.Add(modelItem.GetCurrentValue());
302 ICompositeView container = (ICompositeView)DragDropHelper.GetCompositeView((WorkflowViewElement)modelItem.View);
303 if (container != null)
305 //If the parent and some of its children are selected and cut/copied, we ignore the children.
306 //The entire parent will be cut/copied.
307 //HashSet parentModelItems contains all the model items in the parent chain of current modelItem.
308 //We use HashSet.IntersectWith operation to determine if one of the parents is set to be cut.
309 HashSet<ModelItem> parentModelItems = CutCopyPasteHelper.GetSelectableParentModelItems(modelItem);
310 parentModelItems.IntersectWith(modelItemsToCutCopy);
311 if (parentModelItems.Count == 0)
313 if (!notifyDictionary.ContainsKey(container))
315 notifyDictionary[container] = new List<ModelItem>();
317 notifyDictionary[container].Add(modelItem);
325 foreach (ICompositeView container in notifyDictionary.Keys)
327 object containerMetaData = false;
330 containerMetaData = container.OnItemsCut(notifyDictionary[container]);
334 containerMetaData = container.OnItemsCopied(notifyDictionary[container]);
336 if (containerMetaData != null)
338 metaData.Add(containerMetaData);
340 //Put the actual activities and not the modelItems in the clipboard.
341 foreach (ModelItem modelItem in notifyDictionary[container])
343 objectsOnClipboard.Add(modelItem.GetCurrentValue());
346 if (metaData.Count == 0)
353 FrameworkName targetFramework = context.Services.GetService<DesignerConfigurationService>().TargetFrameworkName;
354 PutOnClipBoard(objectsOnClipboard, metaData, targetFramework);
356 catch (XamlObjectReaderException exception)
358 if (modelItemsToCutCopy.Count > 0 && ErrorActivity.GetHasErrorActivities(modelItemsToCutCopy[0].Root.GetCurrentValue()))
360 ErrorReporting.ShowErrorMessage(SR.CutCopyErrorActivityMessage);
364 ErrorReporting.ShowErrorMessage(exception.Message);
369 //This method collects all the ModelItems in the parent chain by calling the GetSelectableParentViewElements method
370 //which walks the WPF Visual tree. We want to avoid walking ModelItem tree.
371 internal static HashSet<ModelItem> GetSelectableParentModelItems(ModelItem modelItem)
373 if (null == modelItem)
375 throw FxTrace.Exception.ArgumentNull("modelItem");
377 List<WorkflowViewElement> parentViewElements = GetSelectableParentViewElements(modelItem.View as WorkflowViewElement);
378 HashSet<ModelItem> parentModelItems = new HashSet<ModelItem>();
379 foreach (WorkflowViewElement view in parentViewElements)
381 parentModelItems.Add(view.ModelItem);
383 return parentModelItems;
386 //This is more efficient than walking up the VisualTree looking for WorkflowViewElements.
387 //Assuming that Cut-Copy will always be against selected elements.
388 //This implies that only elements under the BreadCrumbRoot can be cut/copied.
389 static List<WorkflowViewElement> GetSelectableParentViewElements(WorkflowViewElement childElement)
391 List<WorkflowViewElement> parentViewElements = new List<WorkflowViewElement>();
392 if (childElement != null)
394 UIElement breadcrumbRoot = childElement.Context.Services.GetService<DesignerView>().RootDesigner;
395 ICompositeView container = (ICompositeView)DragDropHelper.GetCompositeView(childElement);
396 while (!childElement.Equals(breadcrumbRoot) && container != null)
398 childElement = CutCopyPasteHelper.GetParentViewElement(container);
399 Fx.Assert(childElement != null, "container should be present in a WorkflowViewElement");
400 parentViewElements.Add(childElement);
401 container = (ICompositeView)DragDropHelper.GetCompositeView(childElement);
404 return parentViewElements;
407 public static void DoPaste(EditingContext context)
411 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
413 DoPaste(context, new Point(-1, -1), null);
416 internal static void DoPaste(EditingContext context, Point pastePoint, WorkflowViewElement pastePointReference)
420 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
423 ModelItem modelItem = context.Items.GetValue<Selection>().PrimarySelection;
424 if (modelItem == null)
429 //Get data from clipboard.
430 List<object> metaData = null;
431 List<object> clipboardObjects = GetFromClipboard(out metaData, context);
432 if (clipboardObjects != null)
434 using (EditingScope es = (EditingScope)modelItem.BeginEdit(SR.PasteUndoDescription))
436 if (clipboardObjects.Count == 3 && clipboardObjects[1] is Func<ModelItem, object, object>)
438 var factoryMethod = (Func<ModelItem, object, object>)clipboardObjects[1];
439 object result = factoryMethod(modelItem, clipboardObjects[2]);
440 clipboardObjects = new List<object>();
441 clipboardObjects.Add(result);
443 ICompositeView container = GetContainerForPaste(modelItem, pastePoint);
444 if (container != null)
446 container.OnItemsPasted(clipboardObjects, metaData, pastePoint, pastePointReference);
453 static ICompositeView GetClickedContainer(ModelItem clickedModelItem, Point clickPoint)
455 Visual parentVisual = clickedModelItem.View as Visual;
456 if (parentVisual == null)
461 DependencyObject visualHit = null;
462 HitTestResult hitTest = VisualTreeHelper.HitTest(parentVisual, clickPoint);
465 visualHit = hitTest.VisualHit;
466 while (visualHit != null && !visualHit.Equals(parentVisual) &&
467 !typeof(ICompositeView).IsAssignableFrom(visualHit.GetType()))
469 visualHit = VisualTreeHelper.GetParent(visualHit);
472 return visualHit as ICompositeView;
476 static ICompositeView GetContainerForPaste(ModelItem pasteModelItem, Point clickPoint)
478 ICompositeView pasteContainer = null;
480 if (null != pasteModelItem && null != pasteModelItem.View && pasteModelItem.View is WorkflowViewElement)
482 pasteContainer = ((WorkflowViewElement)pasteModelItem.View).ActiveCompositeView;
484 if (null == pasteContainer)
486 //Get clicked container.
487 if (clickPoint.X > 0 && clickPoint.Y > 0)
489 pasteContainer = GetClickedContainer(pasteModelItem, clickPoint);
492 //If the container itself is a WVE, there's posibility that it's collapsed.
493 //Thus, we need to check this as well.
494 if (pasteContainer != null && pasteContainer is WorkflowViewElement)
496 WorkflowViewElement view = pasteContainer as WorkflowViewElement;
497 if (!view.ShowExpanded)
499 pasteContainer = null;
502 else if (pasteContainer == null) //If the modelitem.View itself is a container.
504 WorkflowViewElement view = pasteModelItem.View as WorkflowViewElement;
505 if (view != null && view.ShowExpanded)
507 pasteContainer = pasteModelItem.View as ICompositeView;
511 //Get the container registered with modelItem.View if unambigous
512 //If nothing works take the container with keyboard focus if one exists.
513 if (pasteContainer == null)
515 HashSet<ICompositeView> childrenContainers = CutCopyPasteHelper.GetChildContainers(pasteModelItem.View as WorkflowViewElement);
516 if ((childrenContainers == null || childrenContainers.Count == 0) && null != pasteModelItem.View)
518 pasteContainer = (ICompositeView)DragDropHelper.GetCompositeView((WorkflowViewElement)pasteModelItem.View);
520 else if (null != childrenContainers && childrenContainers.Count == 1)
522 pasteContainer = new List<ICompositeView>(childrenContainers)[0];
526 pasteContainer = Keyboard.FocusedElement as ICompositeView;
531 return pasteContainer;
534 private static void PutOnClipBoard(List<object> selectedData, List<object> metaData, FrameworkName targetFramework)
536 CutCopyPasteHelper.workflowCallbackContext = null;
537 if (selectedData != null)
539 ClipboardData clipboardData = new ClipboardData();
540 clipboardData.Data = selectedData;
541 clipboardData.Metadata = metaData;
542 clipboardData.Version = versionInfo;
544 XamlReader reader = ViewStateXamlHelper.RemoveIdRefs(new XamlObjectReader(clipboardData));
545 StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
546 XamlServices.Transform(reader, new XamlXmlWriter(stringWriter, reader.SchemaContext), true);
547 string clipBoardString = stringWriter.ToString();
549 DataObject dataObject = new DataObject(WorkflowClipboardFormat, clipBoardString);
550 dataObject.SetData(DataFormats.Text, clipBoardString);
551 dataObject.SetData(WorkflowClipboardFormat_TargetFramework, targetFramework);
552 RetriableClipboard.SetDataObject(dataObject, true);
556 //PutCallbackOnClipBoard - tries to put into private (this application only) clipboard a callback
557 //to a method. The method will be invoked when user retrieves clipboard content - i.e. by
558 //calling a paste command.
559 //the callback has to be:
561 //- have return value (not void)
562 //- takes 2 input parameters:
563 // * 1 parameter is modelitem - this is a target modelitem upon which callback is to be executed
564 // * 2 parameter is user provided context - any object. Since this callback will be executed within
565 // this application only, there is no need for context to be serializable.
566 internal static void PutCallbackOnClipBoard(Func<ModelItem, object, object> callbackMethod, Type callbackResultType, object context)
568 if (null == callbackMethod || null == context)
570 throw FxTrace.Exception.AsError(new ArgumentNullException(null == callbackMethod ? "callbackMethod" : "context"));
572 ClipboardData clipboardData = new ClipboardData();
573 List<object> data = new List<object>();
574 data.Add(callbackResultType);
575 data.Add(callbackMethod);
576 clipboardData.Data = data;
577 clipboardData.Version = versionInfo;
578 CutCopyPasteHelper.workflowCallbackContext = context;
581 RetriableClipboard.SetDataObject(new DataObject(WorkflowCallbackClipboardFormat, clipboardData, false), false);
583 catch (ExternalException e)
585 ErrorReporting.ShowErrorMessage(e.Message);
589 private static FrameworkName GetTargetFrameworkFromClipboard(DataObject dataObject)
591 Fx.Assert(dataObject != null, "dataObject should not be null");
593 FrameworkName clipboardFrameworkName = null;
594 if (dataObject.GetDataPresent(WorkflowClipboardFormat_TargetFramework))
596 clipboardFrameworkName = TryGetData(dataObject, WorkflowClipboardFormat_TargetFramework) as FrameworkName;
599 if (clipboardFrameworkName == null)
601 clipboardFrameworkName = FrameworkNameConstants.NetFramework40;
604 return clipboardFrameworkName;
607 //This method returns the list of objects put on clipboard by cut/copy.
608 //Out parameter is the metaData information.
609 [SuppressMessage(FxCop.Category.Design, FxCop.Rule.DoNotCatchGeneralExceptionTypes,
610 Justification = "Deserialization of cliboard data might fail. Propagating exceptions might lead to VS crash.")]
611 [SuppressMessage("Reliability", "Reliability108",
612 Justification = "Deserialization of cliboard data might fail. Propagating exceptions might lead to VS crash.")]
613 private static List<object> GetFromClipboard(out List<object> metaData, EditingContext editingContext)
615 Fx.Assert(editingContext != null, "editingContext should not be null");
617 MultiTargetingSupportService multiTargetingService = editingContext.Services.GetService<IMultiTargetingSupportService>() as MultiTargetingSupportService;
618 DesignerConfigurationService config = editingContext.Services.GetService<DesignerConfigurationService>();
619 DataObject dataObject = RetriableClipboard.GetDataObject() as DataObject;
620 List<object> workflowData = null;
623 if (dataObject != null)
625 if (dataObject.GetDataPresent(WorkflowClipboardFormat))
627 bool isCopyingFromHigherFrameworkToLowerFramework = false;
629 if (multiTargetingService != null && config != null)
631 isCopyingFromHigherFrameworkToLowerFramework = GetTargetFrameworkFromClipboard(dataObject).Version > config.TargetFrameworkName.Version;
634 string clipBoardString = (string)TryGetData(dataObject, WorkflowClipboardFormat);
635 using (StringReader stringReader = new StringReader(clipBoardString))
639 XamlSchemaContext schemaContext;
640 if (isCopyingFromHigherFrameworkToLowerFramework)
642 schemaContext = new MultiTargetingXamlSchemaContext(multiTargetingService);
646 schemaContext = new XamlSchemaContext();
649 using (XamlXmlReader xamlXmlReader = new XamlXmlReader(stringReader, schemaContext))
651 ClipboardData clipboardData = (ClipboardData)XamlServices.Load(xamlXmlReader);
652 metaData = clipboardData.Metadata;
653 workflowData = clipboardData.Data;
658 Trace.WriteLine(e.Message);
662 else if (dataObject.GetDataPresent(WorkflowCallbackClipboardFormat))
664 ClipboardData localData = (ClipboardData)TryGetData(dataObject, WorkflowCallbackClipboardFormat);
666 workflowData = localData.Data;
667 workflowData.Add(CutCopyPasteHelper.workflowCallbackContext);
673 private static object TryGetData(DataObject dataObject, string dataFormat)
677 return dataObject.GetData(dataFormat);
679 catch (OutOfMemoryException)
681 Trace.TraceError("OutOfMemoryException thrown from DataObject.");
686 private static bool CanCopy(Type type)
688 foreach (Type disallowedType in CutCopyPasteHelper.DisallowedTypesForCopy)
690 if (disallowedType.IsAssignableFrom(type))
694 if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(disallowedType))
702 private static bool CanCopy(ModelItem item)
704 return null != item.View && item.View is WorkflowViewElement &&
705 null != ((WorkflowViewElement)item.View).ModelItem &&
706 CanCopy(((WorkflowViewElement)item.View).ModelItem.ItemType);
709 public static bool CanCopy(EditingContext context)
713 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
715 Selection selection = context.Items.GetValue<Selection>();
716 return selection.SelectionCount > 0 && selection.SelectedObjects.All(p => CanCopy(p));
719 public static bool CanCut(EditingContext context)
723 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
726 Selection selection = context.Items.GetValue<Selection>();
727 if (null != selection && selection.SelectionCount > 0)
729 DesignerView designerView = context.Services.GetService<DesignerView>();
730 result = selection.SelectedObjects.All(p =>
731 CanCopy(p) && !p.View.Equals(designerView.RootDesigner));
736 public static bool CanPaste(EditingContext context)
740 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
743 ModelItem primarySelection = context.Items.GetValue<Selection>().PrimarySelection;
744 if (null != primarySelection)
746 ICompositeView container = GetContainerForPaste(primarySelection, new Point(-1, -1));
747 if (null != container)
749 DataObject dataObject = RetriableClipboard.GetDataObject() as DataObject;
750 if (null != dataObject)
752 List<object> metaData = null;
753 List<object> itemsToPaste = null;
756 if (dataObject.GetDataPresent(WorkflowClipboardFormat))
758 itemsToPaste = GetFromClipboard(out metaData, context);
759 result = container.CanPasteItems(itemsToPaste);
761 else if (dataObject.GetDataPresent(WorkflowCallbackClipboardFormat))
763 itemsToPaste = GetFromClipboard(out metaData, context);
764 result = container.CanPasteItems(itemsToPaste.GetRange(0, 1));
767 //This is being defensive for the case where user code for CanPasteITems throws a non-fatal exception.
768 catch (Exception exp)