Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Ink / ClipboardProcessor.cs / 1305600 / ClipboardProcessor.cs
//----------------------------------------------------------------------------
//
// File: ClipboardProcessor.cs
//
// Description:
// A helper class which deals with the operations related to the clipboard.
//
// Features:
//
// History:
// 11/17/2004 waynezen: Created
//
// Copyright (C) 2001 by Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------------------
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Media;
using System.Windows.Markup;
using System.Xml;
using MS.Internal.PresentationFramework; //security helper
namespace MS.Internal.Ink
{
// The bits which internally represents the formats supported by InkCanvas
[System.Flags]
internal enum InkCanvasClipboardDataFormats
{
None = 0x00, // None
XAML = 0x01, // XAML
ISF = 0x02, // ISF
}
///
/// ClipboardProcessor acts as a brige between InkCanvas and various clipboard data formats
/// It provides the functionalies -
/// 1. Check the supported data formats in an IDataObject
/// 2. Copy the selections in an InkCavans to an IDataObject
/// 3. Create the stroks or frameworkelement array if there is any supported data in an IDataObject
///
internal class ClipboardProcessor
{
//-------------------------------------------------------------------------------
//
// Constructors
//
//-------------------------------------------------------------------------------
#region Constructors
internal ClipboardProcessor(InkCanvas inkCanvas)
{
if ( inkCanvas == null )
{
throw new ArgumentNullException("inkCanvas");
}
_inkCanvas = inkCanvas;
// Create our default preferred list - Only InkCanvasClipboardFormat.Isf is supported.
_preferredClipboardData = new Dictionary();
_preferredClipboardData.Add(InkCanvasClipboardFormat.InkSerializedFormat, new ISFClipboardData());
}
#endregion Constructors
//--------------------------------------------------------------------------------
//
// Internal Methods
//
//-------------------------------------------------------------------------------
#region Internal Methods
///
/// This method returns the bits flag if there are the supported data in the IDataObject.
///
/// The IDataObject instance
/// The matched clipboard format. Return -1 if there is no recognized format in the data object
internal bool CheckDataFormats(IDataObject dataObject)
{
Debug.Assert(dataObject != null && _preferredClipboardData!= null);
foreach ( KeyValuePair pair in _preferredClipboardData )
{
if ( pair.Value.CanPaste(dataObject) )
{
return true;
}
}
return false;
}
///
/// The method copies the current selection to the IDataObject if there is any
/// Called by :
/// InkCanvas.CopyToDataObject
///
/// The IDataObject instance
/// true if there is data being copied. Otherwise return false
///
/// Critical: This code copies ink content to the clipboard
/// Note the TAS boundary is InkCanvas.CopyToDataObject
///
[SecurityCritical]
internal InkCanvasClipboardDataFormats CopySelectedData(IDataObject dataObject)
{
InkCanvasClipboardDataFormats copiedDataFormat = InkCanvasClipboardDataFormats.None;
InkCanvasSelection inkCanvasSelection = InkCanvas.InkCanvasSelection;
StrokeCollection strokes = inkCanvasSelection.SelectedStrokes;
if (strokes.Count > 1)
{
// NTRAID#WINDOWS-1541633-2006/03/03-SAMGEO,
// order the strokes so they are in the correct z-order
// they appear in on the InkCanvas, or else they will be inconsistent
// if copied / pasted
StrokeCollection orderedStrokes = new StrokeCollection();
StrokeCollection inkCanvasStrokes = InkCanvas.Strokes; //cache to avoid multiple property gets
for (int i = 0; i < inkCanvasStrokes.Count && strokes.Count != orderedStrokes.Count; i++)
{
for (int j = 0; j < strokes.Count; j++)
{
if (inkCanvasStrokes[i] == strokes[j])
{
orderedStrokes.Add(strokes[j]);
break;
}
}
}
Debug.Assert(inkCanvasSelection.SelectedStrokes.Count == orderedStrokes.Count);
//Make a copy collection since we will alter the transform before copying the data.
strokes = orderedStrokes.Clone();
}
else
{
//we only have zero or one stroke so we don't need to order, but we
//do need to clone.
strokes = strokes.Clone();
}
List elements = new List(inkCanvasSelection.SelectedElements);
Rect bounds = inkCanvasSelection.SelectionBounds;
// Now copy the selection in the below orders.
if ( strokes.Count != 0 || elements.Count != 0 )
{
// NTRAID-WINDOWS#1412097-2005/12/08-WAYNEZEN,
// The selection should be translated to the origin (0, 0) related to its bounds.
// Get the translate transform as a relative bounds.
Matrix transform = Matrix.Identity;
transform.OffsetX = -bounds.Left;
transform.OffsetY = -bounds.Top;
// Add ISF data first.
if ( strokes.Count != 0 )
{
// Transform the strokes first.
inkCanvasSelection.TransformStrokes(strokes, transform);
ClipboardData data = new ISFClipboardData(strokes);
data.CopyToDataObject(dataObject);
copiedDataFormat |= InkCanvasClipboardDataFormats.ISF;
}
// Then add XAML data.
if ( CopySelectionInXAML(dataObject, strokes, elements, transform, bounds.Size) )
{
// We have to create an InkCanvas as a container and add all the selection to it.
copiedDataFormat |= InkCanvasClipboardDataFormats.XAML;
}
}
else
{
Debug.Assert(false , "CopySelectData: InkCanvas should have a selection!");
}
return copiedDataFormat;
}
///
/// The method returns the Strokes or UIElement array if there is the supported data in the IDataObject
///
/// The IDataObject instance
/// The strokes which are converted from the data in the IDataObject
/// The elements array which are converted from the data in the IDataObject
internal bool PasteData(IDataObject dataObject, ref StrokeCollection newStrokes, ref List newElements)
{
Debug.Assert(dataObject != null && _preferredClipboardData!= null);
// We honor the order in our preferred list.
foreach ( KeyValuePair pair in _preferredClipboardData )
{
InkCanvasClipboardFormat format = pair.Key;
ClipboardData data = pair.Value;
if ( data.CanPaste(dataObject) )
{
switch ( format )
{
case InkCanvasClipboardFormat.Xaml:
{
XamlClipboardData xamlData = (XamlClipboardData)data;
xamlData.PasteFromDataObject(dataObject);
List elements = xamlData.Elements;
if (elements != null && elements.Count != 0)
{
// If the Xaml data has been set in an InkCanvas, the top element will be a container InkCanvas.
// In this case, the new elements will be the children of the container.
// Otherwise, the new elements will be whatever data from the data object.
if (elements.Count == 1 && ClipboardProcessor.InkCanvasDType.IsInstanceOfType(elements[0]))
{
TearDownInkCanvasContainer((InkCanvas)( elements[0] ), ref newStrokes, ref newElements);
}
else
{
// The new elements are the data in the data object.
newElements = elements;
}
}
break;
}
case InkCanvasClipboardFormat.InkSerializedFormat:
{
// Retrieve the stroke data.
ISFClipboardData isfData = (ISFClipboardData)data;
isfData.PasteFromDataObject(dataObject);
newStrokes = isfData.Strokes;
break;
}
case InkCanvasClipboardFormat.Text:
{
// Convert the text data in the data object to a text box element.
TextClipboardData textData = (TextClipboardData)data;
textData.PasteFromDataObject(dataObject);
newElements = textData.Elements;
break;
}
}
// Once we've done pasting, just return now.
return true;
}
}
// Nothing gets pasted.
return false;
}
#endregion Internal Methods
internal IEnumerable PreferredFormats
{
get
{
Debug.Assert(_preferredClipboardData != null);
foreach ( KeyValuePair pair in _preferredClipboardData )
{
yield return pair.Key;
}
}
set
{
Debug.Assert(value != null);
Dictionary preferredData = new Dictionary();
foreach ( InkCanvasClipboardFormat format in value )
{
// If we find the duplicate format in our preferred list, we should just skip it.
if ( !preferredData.ContainsKey(format) )
{
ClipboardData clipboardData = null;
switch ( format )
{
case InkCanvasClipboardFormat.InkSerializedFormat:
clipboardData = new ISFClipboardData();
break;
case InkCanvasClipboardFormat.Xaml:
clipboardData = new XamlClipboardData();
break;
case InkCanvasClipboardFormat.Text:
clipboardData = new TextClipboardData();
break;
default:
throw new ArgumentException(SR.Get(SRID.InvalidClipboardFormat), "value");
}
preferredData.Add(format, clipboardData);
}
}
_preferredClipboardData = preferredData;
}
}
//--------------------------------------------------------------------------------
//
// Private Methods
//
//--------------------------------------------------------------------------------
#region Private Methods
///
/// Copy the current Selection in XAML format.
/// Called by :
/// CopySelectedData
///
///
///
///
///
///
/// True if the copy is succeeded
///
/// Critical: This code calls CopyToDataObject which is critical.
/// Note the TAS boundary is InkCanvas.CopyToDataObject
///
/// TreatAsSafe: We only execute this code if the application has UnmanagedCode permission
///
[SecurityCritical, SecurityTreatAsSafe]
private bool CopySelectionInXAML(IDataObject dataObject, StrokeCollection strokes, List elements, Matrix transform, Size size)
{
//NOTE: after meeting with the partial trust team, we have
//collectively decided to only allow copy / cut of XAML if the caller
//has unmanagedcode permission, else we silently ignore the XAML
if (!SecurityHelper.CheckUnmanagedCodePermission())
{
return false;
}
else
{
InkCanvas inkCanvas = new InkCanvas();
// NOTICE-2005/12/06-WAYNEZEN,
// We already transform the Strokes in CopySelectedData.
if (strokes.Count != 0)
{
inkCanvas.Strokes = strokes;
}
int elementCount = elements.Count;
if (elementCount != 0)
{
InkCanvasSelection inkCanvasSelection = InkCanvas.InkCanvasSelection;
for (int i = 0; i < elementCount; i++)
{
// NOTICE-2005/05/05-WAYNEZEN,
// An element can't be added to two visual trees.
// So, we cannot add the elements to the new container since they have been added to the current InkCanvas.
// Here we have to do is according to the suggestion from Avalon team -
// 1. Presist the elements to Xaml
// 2. Load the xaml to create the new instances of the elements.
// 3. Add the new instances to the new container.
string xml;
try
{
xml = XamlWriter.Save(elements[i]);
UIElement newElement = XamlReader.Load(new XmlTextReader(new StringReader(xml))) as UIElement;
((IAddChild)inkCanvas).AddChild(newElement);
// Now we tranform the element.
inkCanvasSelection.UpdateElementBounds(elements[i], newElement, transform);
}
catch (SecurityException)
{
// If we hit a SecurityException under the PartialTrust, we should just stop generating
// the containing InkCanvas.
inkCanvas = null;
break;
}
}
}
if (inkCanvas != null)
{
inkCanvas.Width = size.Width;
inkCanvas.Height = size.Height;
ClipboardData data = new XamlClipboardData(new UIElement[] { inkCanvas });
try
{
data.CopyToDataObject(dataObject);
}
catch (SecurityException)
{
// If we hit a SecurityException under the PartialTrust, we should just fail the copy
// operation.
inkCanvas = null;
}
}
return inkCanvas != null;
}
}
private void TearDownInkCanvasContainer(InkCanvas rootInkCanvas, ref StrokeCollection newStrokes, ref List newElements)
{
newStrokes = rootInkCanvas.Strokes;
if ( rootInkCanvas.Children.Count != 0 )
{
List children = new List(rootInkCanvas.Children.Count);
foreach (UIElement uiElement in rootInkCanvas.Children)
{
children.Add(uiElement);
}
// Remove the children for the container
foreach ( UIElement child in children )
{
rootInkCanvas.Children.Remove(child);
}
// The new elements will be the children.
newElements = children;
}
}
#endregion Private Methods
//-------------------------------------------------------------------------------
//
// Private Properties
//
//--------------------------------------------------------------------------------
#region Private Properties
private InkCanvas InkCanvas
{
get
{
return _inkCanvas;
}
}
///
/// A static DependencyObjectType of the GrabHandleAdorner which can be used for quick type checking.
///
/// An DependencyObjectType object
private static DependencyObjectType InkCanvasDType
{
get
{
if ( s_InkCanvasDType == null )
{
s_InkCanvasDType = DependencyObjectType.FromSystemTypeInternal(typeof(InkCanvas));
}
return s_InkCanvasDType;
}
}
#endregion Private Properties
//-------------------------------------------------------------------------------
//
// Private Fields
//
//-------------------------------------------------------------------------------
#region Private Fields
private InkCanvas _inkCanvas;
private static DependencyObjectType s_InkCanvasDType;
private Dictionary _preferredClipboardData;
#endregion Private Fields
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- LineServicesCallbacks.cs
- WorkflowElementDialog.cs
- DataPagerFieldItem.cs
- HtmlTableRow.cs
- FragmentQueryProcessor.cs
- TableHeaderCell.cs
- FtpCachePolicyElement.cs
- UTF7Encoding.cs
- ConversionContext.cs
- DateTime.cs
- PrimaryKeyTypeConverter.cs
- XmlSchemaDatatype.cs
- WebPartTransformer.cs
- FileDialogPermission.cs
- FontWeightConverter.cs
- UnicastIPAddressInformationCollection.cs
- DesignerProperties.cs
- DrawingCollection.cs
- Part.cs
- SudsWriter.cs
- TreeIterators.cs
- FrameworkElementAutomationPeer.cs
- ConditionCollection.cs
- DesignerHierarchicalDataSourceView.cs
- LocalFileSettingsProvider.cs
- TypeSystem.cs
- TabControl.cs
- LocatorPartList.cs
- Misc.cs
- NumericUpDownAccelerationCollection.cs
- ThreadExceptionDialog.cs
- DetailsViewDeleteEventArgs.cs
- GroupByExpressionRewriter.cs
- ParseElement.cs
- DataServiceQueryOfT.cs
- DeflateEmulationStream.cs
- BreakRecordTable.cs
- Config.cs
- ChangeProcessor.cs
- Accessible.cs
- SmtpMail.cs
- TextSelectionHelper.cs
- XmlWrappingWriter.cs
- ArgIterator.cs
- EntityContainer.cs
- ListDependantCardsRequest.cs
- ColumnWidthChangedEvent.cs
- SoapCodeExporter.cs
- ToolStripComboBox.cs
- LogExtentCollection.cs
- SortedList.cs
- BamlMapTable.cs
- QuarticEase.cs
- CngProvider.cs
- SchemaConstraints.cs
- TreeIterators.cs
- SoapHeader.cs
- WebBaseEventKeyComparer.cs
- Compilation.cs
- MultipleViewProviderWrapper.cs
- InitializerFacet.cs
- GenericUriParser.cs
- SecurityHelper.cs
- NullableConverter.cs
- HtmlForm.cs
- ExpressionEditor.cs
- TreeViewHitTestInfo.cs
- ComponentEditorForm.cs
- ProtocolViolationException.cs
- PackagePart.cs
- CapabilitiesAssignment.cs
- BatchParser.cs
- CodeThrowExceptionStatement.cs
- EllipticalNodeOperations.cs
- CipherData.cs
- CharConverter.cs
- SoapTypeAttribute.cs
- PathSegmentCollection.cs
- HtmlTableCellCollection.cs
- OracleLob.cs
- SiblingIterators.cs
- ArrangedElement.cs
- NativeMethods.cs
- UnsafePeerToPeerMethods.cs
- IdentityHolder.cs
- UnsafeNativeMethods.cs
- XmlDocumentSerializer.cs
- Latin1Encoding.cs
- DeflateStream.cs
- ObjectKeyFrameCollection.cs
- DictionaryManager.cs
- infer.cs
- OracleInternalConnection.cs
- RemotingSurrogateSelector.cs
- ModelUIElement3D.cs
- DataTableCollection.cs
- MimeTypePropertyAttribute.cs
- InputLanguageEventArgs.cs
- ComAdminInterfaces.cs
- CrossAppDomainChannel.cs