Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / Ink / DrawingAttributes.cs / 1 / DrawingAttributes.cs
//------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------
using MS.Utility;
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using MS.Internal;
using MS.Internal.Ink;
using MS.Internal.Ink.InkSerializedFormat;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
namespace System.Windows.Ink
{
///
/// DrawingAttributes is the list of attributes applied to an ink stroke
/// when it is drawn. The DrawingAttributes controls stroke color, width,
/// transparency, and more.
///
///
/// Note that when saving the DrawingAttributes, the V1 AntiAlias attribute
/// is always set, and on load the AntiAlias property is ignored.
///
public class DrawingAttributes : INotifyPropertyChanged
{
#region Constructors
///
/// Creates a DrawingAttributes with default values
///
public DrawingAttributes()
{
_extendedProperties = new ExtendedPropertyCollection();
Initialize();
}
///
/// Internal only constructor that initializes a DA with an EPC
///
///
internal DrawingAttributes(ExtendedPropertyCollection extendedProperties)
{
System.Diagnostics.Debug.Assert(extendedProperties != null);
_extendedProperties = extendedProperties;
Initialize();
}
///
/// Common constructor call, also called by Clone
///
private void Initialize()
{
System.Diagnostics.Debug.Assert(_extendedProperties != null);
_extendedProperties.Changed +=
new ExtendedPropertiesChangedEventHandler(this.ExtendedPropertiesChanged_EventForwarder);
}
#endregion Constructors
#region Public Properties
///
/// The color of the Stroke
///
public Color Color
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.Color))
{
Debug.Assert(Colors.Black == (Color)GetDefaultDrawingAttributeValue(KnownIds.Color));
return Colors.Black;
}
return (Color)GetExtendedPropertyBackedProperty(KnownIds.Color);
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
// Validation of value is done in EPC
SetExtendedPropertyBackedProperty(KnownIds.Color, value);
}
}
///
/// The StylusTip used to draw the stroke
///
public StylusTip StylusTip
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.StylusTip))
{
Debug.Assert(StylusTip.Ellipse == (StylusTip)GetDefaultDrawingAttributeValue(KnownIds.StylusTip));
return StylusTip.Ellipse;
}
else
{
//if we ever add to StylusTip enumeration, we need to just return GetExtendedPropertyBackedProperty
Debug.Assert(StylusTip.Rectangle == (StylusTip)GetExtendedPropertyBackedProperty(KnownIds.StylusTip));
return StylusTip.Rectangle;
}
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
// Validation of value is done in EPC
SetExtendedPropertyBackedProperty(KnownIds.StylusTip, value);
}
}
///
/// The StylusTip used to draw the stroke
///
public Matrix StylusTipTransform
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.StylusTipTransform))
{
Debug.Assert(Matrix.Identity == (Matrix)GetDefaultDrawingAttributeValue(KnownIds.StylusTipTransform));
return Matrix.Identity;
}
return (Matrix)GetExtendedPropertyBackedProperty(KnownIds.StylusTipTransform);
}
set
{
Matrix m = (Matrix) value;
if (m.OffsetX != 0 || m.OffsetY != 0)
{
throw new ArgumentException(SR.Get(SRID.InvalidSttValue), "value");
}
//no need to raise change events, they will bubble up from the EPC
//underneath us
// Validation of value is done in EPC
SetExtendedPropertyBackedProperty(KnownIds.StylusTipTransform, value);
}
}
///
/// The height of the StylusTip
///
public double Height
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.StylusHeight))
{
Debug.Assert(DrawingAttributes.DefaultHeight == (double)GetDefaultDrawingAttributeValue(KnownIds.StylusHeight));
return DrawingAttributes.DefaultHeight;
}
return (double)GetExtendedPropertyBackedProperty(KnownIds.StylusHeight);
}
set
{
if (double.IsNaN(value) || value < MinHeight || value > MaxHeight)
{
throw new ArgumentOutOfRangeException("Height", SR.Get(SRID.InvalidDrawingAttributesHeight));
}
//no need to raise change events, they will bubble up from the EPC
//underneath us
SetExtendedPropertyBackedProperty(KnownIds.StylusHeight, value);
}
}
///
/// The width of the StylusTip
///
public double Width
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.StylusWidth))
{
Debug.Assert(DrawingAttributes.DefaultWidth == (double)GetDefaultDrawingAttributeValue(KnownIds.StylusWidth));
return DrawingAttributes.DefaultWidth;
}
return (double)GetExtendedPropertyBackedProperty(KnownIds.StylusWidth);
}
set
{
if (double.IsNaN(value) || value < MinWidth || value > MaxWidth)
{
throw new ArgumentOutOfRangeException("Width", SR.Get(SRID.InvalidDrawingAttributesWidth));
}
//no need to raise change events, they will bubble up from the EPC
//underneath us
SetExtendedPropertyBackedProperty(KnownIds.StylusWidth, value);
}
}
///
/// When true, ink will be rendered as a series of curves instead of as
/// lines between Stylus sample points. This is useful for smoothing the ink, especially
/// when the person writing the ink has jerky or shaky writing.
/// This value is TRUE by default in the Avalon implementation
///
public bool FitToCurve
{
get
{
DrawingFlags flags = (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
return (0 != (flags & DrawingFlags.FitToCurve));
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
DrawingFlags flags = (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
if (value)
{
//turn on the bit
flags |= DrawingFlags.FitToCurve;
}
else
{
//turn off the bit
flags &= ~DrawingFlags.FitToCurve;
}
SetExtendedPropertyBackedProperty(KnownIds.DrawingFlags, flags);
}
}
///
/// When true, ink will be rendered with any available pressure information
/// taken into account
///
public bool IgnorePressure
{
get
{
DrawingFlags flags = (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
return (0 != (flags & DrawingFlags.IgnorePressure));
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
DrawingFlags flags = (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
if (value)
{
//turn on the bit
flags |= DrawingFlags.IgnorePressure;
}
else
{
//turn off the bit
flags &= ~DrawingFlags.IgnorePressure;
}
SetExtendedPropertyBackedProperty(KnownIds.DrawingFlags, flags);
}
}
///
/// Determines if the stroke should be treated as a highlighter
///
public bool IsHighlighter
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.IsHighlighter))
{
Debug.Assert(false == (bool)GetDefaultDrawingAttributeValue(KnownIds.IsHighlighter));
return false;
}
else
{
Debug.Assert(true == (bool)GetExtendedPropertyBackedProperty(KnownIds.IsHighlighter));
return true;
}
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
SetExtendedPropertyBackedProperty(KnownIds.IsHighlighter, value);
//
// set RasterOp for V1 interop
//
if (value)
{
_v1RasterOperation = DrawingAttributeSerializer.RasterOperationMaskPen;
}
else
{
_v1RasterOperation = DrawingAttributeSerializer.RasterOperationDefaultV1;
}
}
}
#region Extended Properties
///
/// Allows addition of objects to the EPC
///
///
///
public void AddPropertyData(Guid propertyDataId, object propertyData)
{
DrawingAttributes.ValidateStylusTipTransform(propertyDataId, propertyData);
SetExtendedPropertyBackedProperty(propertyDataId, propertyData);
}
///
/// Allows removal of objects from the EPC
///
///
public void RemovePropertyData(Guid propertyDataId)
{
this.ExtendedProperties.Remove(propertyDataId);
}
///
/// Allows retrieval of objects from the EPC
///
///
public object GetPropertyData(Guid propertyDataId)
{
return GetExtendedPropertyBackedProperty(propertyDataId);
}
///
/// Allows retrieval of a Array of guids that are contained in the EPC
///
public Guid[] GetPropertyDataIds()
{
return this.ExtendedProperties.GetGuidArray();
}
///
/// Allows check of containment of objects to the EPC
///
///
public bool ContainsPropertyData(Guid propertyDataId)
{
return this.ExtendedProperties.Contains(propertyDataId);
}
///
/// ExtendedProperties
///
internal ExtendedPropertyCollection ExtendedProperties
{
get
{
return _extendedProperties;
}
}
///
/// Returns a copy of the EPC
///
internal ExtendedPropertyCollection CopyPropertyData()
{
return this.ExtendedProperties.Clone();
}
#endregion
#endregion
#region Internal Properties
///
/// StylusShape
///
internal StylusShape StylusShape
{
get
{
StylusShape s;
if (this.StylusTip == StylusTip.Rectangle)
{
s = new RectangleStylusShape(this.Width, this.Height);
}
else
{
s = new EllipseStylusShape(this.Width, this.Height);
}
s.Transform = StylusTipTransform;
return s;
}
}
///
/// Sets the Fitting error for this drawing attributes
///
internal int FittingError
{
get
{
if (!_extendedProperties.Contains(KnownIds.CurveFittingError))
{
return 0;
}
else
{
return (int)_extendedProperties[KnownIds.CurveFittingError];
}
}
set
{
_extendedProperties[KnownIds.CurveFittingError] = value;
}
}
///
/// Sets the Fitting error for this drawing attributes
///
internal DrawingFlags DrawingFlags
{
get
{
return (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
SetExtendedPropertyBackedProperty(KnownIds.DrawingFlags, value);
}
}
///
/// we need to preserve this for round tripping
///
///
internal uint RasterOperation
{
get
{
return _v1RasterOperation;
}
set
{
_v1RasterOperation = value;
}
}
///
/// When we load ISF from V1 if width is set and height is not
/// and PenTip is Circle, we need to set height to the same as width
/// or else we'll render different as an Ellipse. We use this flag to
/// preserve state for round tripping.
///
internal bool HeightChangedForCompatabity
{
get { return _heightChangedForCompatabity; }
set { _heightChangedForCompatabity = value; }
}
#endregion
//-----------------------------------------------------
//
// INotifyPropertyChanged Interface
//
//-----------------------------------------------------
#region INotifyPropertyChanged Interface
///
/// INotifyPropertyChanged.PropertyChanged event
///
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { _propertyChanged += value; }
remove { _propertyChanged -= value; }
}
#endregion INotifyPropertyChanged Interface
#region Methods
#region Object overrides
// NTRAID#T2-23041-2003/10/01-[....]: SPECISSUE: What should ExtendedPropertyCollection.GetHashCode return?
/// Retrieve an integer-based value for using ExtendedPropertyCollection
/// objects in a hash table as keys
public override int GetHashCode()
{
return base.GetHashCode();
}
/// Overload of the Equals method which determines if two DrawingAttributes
/// objects contain the same drawing attributes
public override bool Equals(object o)
{
if (o == null || o.GetType() != this.GetType())
{
return false;
}
//use as and check for null instead of casting to DA to make presharp happy
DrawingAttributes that = o as DrawingAttributes;
if (that == null)
{
return false;
}
return (this._extendedProperties == that._extendedProperties);
}
/// Overload of the equality operator which determines
/// if two DrawingAttributes are equal
public static bool operator ==(DrawingAttributes first, DrawingAttributes second)
{
// compare the GC ptrs for the obvious reference equality
if (((object)first == null && (object)second == null) ||
((object)first == (object)second))
{
return true;
}
// otherwise, if one of the ptrs are null, but not the other then return false
else if ((object)first == null || (object)second == null)
{
return false;
}
// finally use the full `blown value-style comparison against the collection contents
return first.Equals(second);
}
/// Overload of the not equals operator to determine if two
/// DrawingAttributes are different
public static bool operator !=(DrawingAttributes first, DrawingAttributes second)
{
return !(first == second);
}
#endregion
///
/// Copies the DrawingAttributes
///
/// Deep copy of the DrawingAttributes
///
public virtual DrawingAttributes Clone()
{
//
// use MemberwiseClone, which will instance the most derived type
// We use this instead of Activator.CreateInstance because it does not
// require ReflectionPermission. One thing to note, all references
// are shared, including event delegates, so we need to set those to null
//
DrawingAttributes clone = (DrawingAttributes)this.MemberwiseClone();
//
// null the delegates in the cloned DrawingAttributes
//
clone.AttributeChanged = null;
clone.PropertyDataChanged = null;
//make a copy of the epc , set up listeners
clone._extendedProperties = _extendedProperties.Clone();
clone.Initialize();
//don't need to clone these, it is a value type
//and is copied by MemberwiseClone
//_v1RasterOperation
//_heightChangedForCompatabity
return clone;
}
#endregion
#region Events
///
/// Event fired whenever a DrawingAttribute is modified
///
public event PropertyDataChangedEventHandler AttributeChanged;
///
/// Method called when a change occurs to any DrawingAttribute
///
/// The change information for the DrawingAttribute that was modified
protected virtual void OnAttributeChanged(PropertyDataChangedEventArgs e)
{
if (null == e)
{
throw new ArgumentNullException("e", SR.Get(SRID.EventArgIsNull));
}
try
{
PrivateNotifyPropertyChanged(e);
}
finally
{
if ( this.AttributeChanged != null )
{
this.AttributeChanged(this, e);
}
}
}
///
/// Event fired whenever a DrawingAttribute is modified
///
public event PropertyDataChangedEventHandler PropertyDataChanged;
///
/// Method called when a change occurs to any PropertyData
///
/// The change information for the PropertyData that was modified
protected virtual void OnPropertyDataChanged(PropertyDataChangedEventArgs e)
{
if (null == e)
{
throw new ArgumentNullException("e", SR.Get(SRID.EventArgIsNull));
}
if (this.PropertyDataChanged != null)
{
this.PropertyDataChanged(this, e);
}
}
#endregion
#region Protected Methods
///
/// Method called when a property change occurs to DrawingAttribute
///
/// The EventArgs specifying the name of the changed property.
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if ( _propertyChanged != null )
{
_propertyChanged(this, e);
}
}
#endregion Protected Methods
#region Private Methods
///
/// Simple helper method used to determine if a guid
/// from an ExtendedProperty is used as the backing store
/// of a DrawingAttribute
///
///
///
internal static object GetDefaultDrawingAttributeValue(Guid id)
{
if (KnownIds.Color == id)
{
return Colors.Black;
}
if (KnownIds.StylusWidth == id)
{
return DrawingAttributes.DefaultWidth;
}
if (KnownIds.StylusTip == id)
{
return StylusTip.Ellipse;
}
if (KnownIds.DrawingFlags == id)
{
//note that in this implementation, FitToCurve is false by default
return DrawingFlags.AntiAliased;
}
if (KnownIds.StylusHeight == id)
{
return DrawingAttributes.DefaultHeight;
}
if (KnownIds.StylusTipTransform == id)
{
return Matrix.Identity;
}
if (KnownIds.IsHighlighter == id)
{
return false;
}
// this is a valid case
// as this helper method is used not only to
// get the default value, but also to see if
// the Guid is a drawing attribute value
return null;
}
internal static void ValidateStylusTipTransform(Guid propertyDataId, object propertyData)
{
// NTRAID#WINOS-1136720-2005/06/22-XIAOTU:
// Calling AddPropertyData(KnownIds.StylusTipTransform, "d") does not throw an ArgumentException.
// ExtendedPropertySerializer.Validate take a string as a valid type since StylusTipTransform
// gets serialized as a String, but at runtime is a Matrix
if (propertyData == null)
{
throw new ArgumentNullException("propertyData");
}
else if (propertyDataId == KnownIds.StylusTipTransform)
{
// StylusTipTransform gets serialized as a String, but at runtime is a Matrix
Type t = propertyData.GetType();
if (t == typeof(String))
{
throw new ArgumentException(SR.Get(SRID.InvalidValueType, typeof(Matrix)), "propertyData");
}
}
}
///
/// Simple helper method used to determine if a guid
/// needs to be removed from the ExtendedPropertyCollection in ISF
/// before serializing
///
///
///
internal static bool RemoveIdFromExtendedProperties(Guid id)
{
if (KnownIds.Color == id ||
KnownIds.Transparency == id ||
KnownIds.StylusWidth == id ||
KnownIds.DrawingFlags == id ||
KnownIds.StylusHeight == id ||
KnownIds.CurveFittingError == id )
{
return true;
}
return false;
}
///
/// Returns true if two DrawingAttributes lead to the same PathGeometry.
///
internal static bool GeometricallyEqual(DrawingAttributes left, DrawingAttributes right)
{
// Optimization case:
// must correspond to the same path geometry if they refer to the same instance.
if (Object.ReferenceEquals(left, right))
{
return true;
}
if (left.StylusTip == right.StylusTip &&
left.StylusTipTransform == right.StylusTipTransform &&
DoubleUtil.AreClose(left.Width, right.Width) &&
DoubleUtil.AreClose(left.Height, right.Height) &&
left.DrawingFlags == right.DrawingFlags /*contains IgnorePressure / FitToCurve*/)
{
return true;
}
return false;
}
///
/// Returns true if the guid passed in has impact on geometry of the stroke
///
internal static bool IsGeometricalDaGuid(Guid guid)
{
// Assert it is a DA guid
System.Diagnostics.Debug.Assert(null != DrawingAttributes.GetDefaultDrawingAttributeValue(guid));
if (guid == KnownIds.StylusHeight || guid == KnownIds.StylusWidth ||
guid == KnownIds.StylusTipTransform || guid == KnownIds.StylusTip ||
guid == KnownIds.DrawingFlags)
{
return true;
}
return false;
}
///
/// Whenever the base class fires the generic ExtendedPropertiesChanged
/// event, we need to fire the DrawingAttributesChanged event also.
///
/// Should be 'this' object
/// The custom attributes that changed
private void ExtendedPropertiesChanged_EventForwarder(object sender, ExtendedPropertiesChangedEventArgs args)
{
System.Diagnostics.Debug.Assert(sender != null);
System.Diagnostics.Debug.Assert(args != null);
//see if the EP that changed is a drawingattribute
if (args.NewProperty == null)
{
//a property was removed, see if it is a drawing attribute property
object defaultValueIfDrawingAttribute
= DrawingAttributes.GetDefaultDrawingAttributeValue(args.OldProperty.Id);
if (defaultValueIfDrawingAttribute != null)
{
ExtendedProperty newProperty =
new ExtendedProperty( args.OldProperty.Id,
defaultValueIfDrawingAttribute);
//this is a da guid
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.OldProperty.Id,
newProperty.Value, //the property
args.OldProperty.Value);//previous value
this.OnAttributeChanged(dargs);
}
else
{
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.OldProperty.Id,
null, //the property
args.OldProperty.Value);//previous value
this.OnPropertyDataChanged(dargs);
}
}
else if (args.OldProperty == null)
{
//a property was added, see if it is a drawing attribute property
object defaultValueIfDrawingAttribute
= DrawingAttributes.GetDefaultDrawingAttributeValue(args.NewProperty.Id);
if (defaultValueIfDrawingAttribute != null)
{
if (!defaultValueIfDrawingAttribute.Equals(args.NewProperty.Value))
{
//this is a da guid
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.NewProperty.Id,
args.NewProperty.Value, //the property
defaultValueIfDrawingAttribute); //previous value
this.OnAttributeChanged(dargs);
}
}
else
{
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs(args.NewProperty.Id,
args.NewProperty.Value, //the property
null); //previous value
this.OnPropertyDataChanged(dargs);
}
}
else
{
//something was modified, see if it is a drawing attribute property
object defaultValueIfDrawingAttribute
= DrawingAttributes.GetDefaultDrawingAttributeValue(args.NewProperty.Id);
if (defaultValueIfDrawingAttribute != null)
{
//
// we only raise DA changed when the value actually changes
//
if (!args.NewProperty.Value.Equals(args.OldProperty.Value))
{
//this is a da guid
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.NewProperty.Id,
args.NewProperty.Value, //the da
args.OldProperty.Value);//old value
this.OnAttributeChanged(dargs);
}
}
else
{
if (!args.NewProperty.Value.Equals(args.OldProperty.Value))
{
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.NewProperty.Id,
args.NewProperty.Value,
args.OldProperty.Value);//old value
this.OnPropertyDataChanged(dargs);
}
}
}
}
///
/// All DrawingAttributes are backed by an ExtendedProperty
/// this is a simple helper to set a property
///
/// id
/// value
private void SetExtendedPropertyBackedProperty(Guid id, object value)
{
if (_extendedProperties.Contains(id))
{
//
// check to see if we're setting the property back
// to a default value. If we are we should remove it from
// the EPC
//
object defaultValue = DrawingAttributes.GetDefaultDrawingAttributeValue(id);
if (defaultValue != null)
{
if (defaultValue.Equals(value))
{
_extendedProperties.Remove(id);
return;
}
}
//
// we're setting a non-default value on a EP that
// already exists, check for equality before we do
// so we don't raise unnecessary EPC changed events
//
object o = GetExtendedPropertyBackedProperty(id);
if (!o.Equals(value))
{
_extendedProperties[id] = value;
}
}
else
{
//
// make sure we're not setting a default value of the guid
// there is no need to do this
//
object defaultValue = DrawingAttributes.GetDefaultDrawingAttributeValue(id);
if (defaultValue == null || !defaultValue.Equals(value))
{
_extendedProperties[id] = value;
}
}
}
///
/// All DrawingAttributes are backed by an ExtendedProperty
/// this is a simple helper to set a property
///
/// id
///
private object GetExtendedPropertyBackedProperty(Guid id)
{
if (!_extendedProperties.Contains(id))
{
if (null != DrawingAttributes.GetDefaultDrawingAttributeValue(id))
{
return DrawingAttributes.GetDefaultDrawingAttributeValue(id);
}
throw new ArgumentException(SR.Get(SRID.EPGuidNotFound), "id");
}
else
{
return _extendedProperties[id];
}
}
///
/// A help method which fires INotifyPropertyChanged.PropertyChanged event
///
///
private void PrivateNotifyPropertyChanged(PropertyDataChangedEventArgs e)
{
if ( e.PropertyGuid == KnownIds.Color)
{
OnPropertyChanged("Color");
}
else if ( e.PropertyGuid == KnownIds.StylusTip)
{
OnPropertyChanged("StylusTip");
}
else if ( e.PropertyGuid == KnownIds.StylusTipTransform)
{
OnPropertyChanged("StylusTipTransform");
}
else if ( e.PropertyGuid == KnownIds.StylusHeight)
{
OnPropertyChanged("Height");
}
else if ( e.PropertyGuid == KnownIds.StylusWidth)
{
OnPropertyChanged("Width");
}
else if ( e.PropertyGuid == KnownIds.IsHighlighter)
{
OnPropertyChanged("IsHighlighter");
}
else if ( e.PropertyGuid == KnownIds.DrawingFlags )
{
DrawingFlags changedBits = ( ( (DrawingFlags)e.PreviousValue ) ^ ( (DrawingFlags)e.NewValue ) );
// NOTICE-2006/01/20-WAYNEZEN,
// If someone changes FitToCurve and IgnorePressure simultaneously via AddPropertyData/RemovePropertyData,
// we will fire both OnPropertyChangeds in advance the order of the values.
if ( (changedBits & DrawingFlags.FitToCurve) != 0 )
{
OnPropertyChanged("FitToCurve");
}
if ( (changedBits & DrawingFlags.IgnorePressure) != 0 )
{
OnPropertyChanged("IgnorePressure");
}
}
}
private void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Private Fields
// The private PropertyChanged event
private PropertyChangedEventHandler _propertyChanged;
private ExtendedPropertyCollection _extendedProperties;
private uint _v1RasterOperation = DrawingAttributeSerializer.RasterOperationDefaultV1;
private bool _heightChangedForCompatabity = false;
///
/// Statics
///
internal static readonly float StylusPrecision = 1000.0f;
internal static readonly double DefaultWidth = 2.0031496062992127;
internal static readonly double DefaultHeight = 2.0031496062992127;
#endregion
///
/// Mininum acceptable stylus tip height, corresponds to 0.001 in V1
///
/// corresponds to 0.001 in V1 (0.001 / (2540/96))
public static readonly double MinHeight = 0.00003779527559055120;
///
/// Minimum acceptable stylus tip width
///
/// corresponds to 0.001 in V1 (0.001 / (2540/96))
public static readonly double MinWidth = 0.00003779527559055120;
///
/// Maximum acceptable stylus tip height.
///
/// corresponds to 4294967 in V1 (4294967 / (2540/96))
public static readonly double MaxHeight = 162329.4614173230;
///
/// Maximum acceptable stylus tip width.
///
/// corresponds to 4294967 in V1 (4294967 / (2540/96))
public static readonly double MaxWidth = 162329.4614173230;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------
using MS.Utility;
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using MS.Internal;
using MS.Internal.Ink;
using MS.Internal.Ink.InkSerializedFormat;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
namespace System.Windows.Ink
{
///
/// DrawingAttributes is the list of attributes applied to an ink stroke
/// when it is drawn. The DrawingAttributes controls stroke color, width,
/// transparency, and more.
///
///
/// Note that when saving the DrawingAttributes, the V1 AntiAlias attribute
/// is always set, and on load the AntiAlias property is ignored.
///
public class DrawingAttributes : INotifyPropertyChanged
{
#region Constructors
///
/// Creates a DrawingAttributes with default values
///
public DrawingAttributes()
{
_extendedProperties = new ExtendedPropertyCollection();
Initialize();
}
///
/// Internal only constructor that initializes a DA with an EPC
///
///
internal DrawingAttributes(ExtendedPropertyCollection extendedProperties)
{
System.Diagnostics.Debug.Assert(extendedProperties != null);
_extendedProperties = extendedProperties;
Initialize();
}
///
/// Common constructor call, also called by Clone
///
private void Initialize()
{
System.Diagnostics.Debug.Assert(_extendedProperties != null);
_extendedProperties.Changed +=
new ExtendedPropertiesChangedEventHandler(this.ExtendedPropertiesChanged_EventForwarder);
}
#endregion Constructors
#region Public Properties
///
/// The color of the Stroke
///
public Color Color
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.Color))
{
Debug.Assert(Colors.Black == (Color)GetDefaultDrawingAttributeValue(KnownIds.Color));
return Colors.Black;
}
return (Color)GetExtendedPropertyBackedProperty(KnownIds.Color);
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
// Validation of value is done in EPC
SetExtendedPropertyBackedProperty(KnownIds.Color, value);
}
}
///
/// The StylusTip used to draw the stroke
///
public StylusTip StylusTip
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.StylusTip))
{
Debug.Assert(StylusTip.Ellipse == (StylusTip)GetDefaultDrawingAttributeValue(KnownIds.StylusTip));
return StylusTip.Ellipse;
}
else
{
//if we ever add to StylusTip enumeration, we need to just return GetExtendedPropertyBackedProperty
Debug.Assert(StylusTip.Rectangle == (StylusTip)GetExtendedPropertyBackedProperty(KnownIds.StylusTip));
return StylusTip.Rectangle;
}
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
// Validation of value is done in EPC
SetExtendedPropertyBackedProperty(KnownIds.StylusTip, value);
}
}
///
/// The StylusTip used to draw the stroke
///
public Matrix StylusTipTransform
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.StylusTipTransform))
{
Debug.Assert(Matrix.Identity == (Matrix)GetDefaultDrawingAttributeValue(KnownIds.StylusTipTransform));
return Matrix.Identity;
}
return (Matrix)GetExtendedPropertyBackedProperty(KnownIds.StylusTipTransform);
}
set
{
Matrix m = (Matrix) value;
if (m.OffsetX != 0 || m.OffsetY != 0)
{
throw new ArgumentException(SR.Get(SRID.InvalidSttValue), "value");
}
//no need to raise change events, they will bubble up from the EPC
//underneath us
// Validation of value is done in EPC
SetExtendedPropertyBackedProperty(KnownIds.StylusTipTransform, value);
}
}
///
/// The height of the StylusTip
///
public double Height
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.StylusHeight))
{
Debug.Assert(DrawingAttributes.DefaultHeight == (double)GetDefaultDrawingAttributeValue(KnownIds.StylusHeight));
return DrawingAttributes.DefaultHeight;
}
return (double)GetExtendedPropertyBackedProperty(KnownIds.StylusHeight);
}
set
{
if (double.IsNaN(value) || value < MinHeight || value > MaxHeight)
{
throw new ArgumentOutOfRangeException("Height", SR.Get(SRID.InvalidDrawingAttributesHeight));
}
//no need to raise change events, they will bubble up from the EPC
//underneath us
SetExtendedPropertyBackedProperty(KnownIds.StylusHeight, value);
}
}
///
/// The width of the StylusTip
///
public double Width
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.StylusWidth))
{
Debug.Assert(DrawingAttributes.DefaultWidth == (double)GetDefaultDrawingAttributeValue(KnownIds.StylusWidth));
return DrawingAttributes.DefaultWidth;
}
return (double)GetExtendedPropertyBackedProperty(KnownIds.StylusWidth);
}
set
{
if (double.IsNaN(value) || value < MinWidth || value > MaxWidth)
{
throw new ArgumentOutOfRangeException("Width", SR.Get(SRID.InvalidDrawingAttributesWidth));
}
//no need to raise change events, they will bubble up from the EPC
//underneath us
SetExtendedPropertyBackedProperty(KnownIds.StylusWidth, value);
}
}
///
/// When true, ink will be rendered as a series of curves instead of as
/// lines between Stylus sample points. This is useful for smoothing the ink, especially
/// when the person writing the ink has jerky or shaky writing.
/// This value is TRUE by default in the Avalon implementation
///
public bool FitToCurve
{
get
{
DrawingFlags flags = (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
return (0 != (flags & DrawingFlags.FitToCurve));
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
DrawingFlags flags = (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
if (value)
{
//turn on the bit
flags |= DrawingFlags.FitToCurve;
}
else
{
//turn off the bit
flags &= ~DrawingFlags.FitToCurve;
}
SetExtendedPropertyBackedProperty(KnownIds.DrawingFlags, flags);
}
}
///
/// When true, ink will be rendered with any available pressure information
/// taken into account
///
public bool IgnorePressure
{
get
{
DrawingFlags flags = (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
return (0 != (flags & DrawingFlags.IgnorePressure));
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
DrawingFlags flags = (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
if (value)
{
//turn on the bit
flags |= DrawingFlags.IgnorePressure;
}
else
{
//turn off the bit
flags &= ~DrawingFlags.IgnorePressure;
}
SetExtendedPropertyBackedProperty(KnownIds.DrawingFlags, flags);
}
}
///
/// Determines if the stroke should be treated as a highlighter
///
public bool IsHighlighter
{
get
{
//prevent boxing / unboxing if possible
if (!_extendedProperties.Contains(KnownIds.IsHighlighter))
{
Debug.Assert(false == (bool)GetDefaultDrawingAttributeValue(KnownIds.IsHighlighter));
return false;
}
else
{
Debug.Assert(true == (bool)GetExtendedPropertyBackedProperty(KnownIds.IsHighlighter));
return true;
}
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
SetExtendedPropertyBackedProperty(KnownIds.IsHighlighter, value);
//
// set RasterOp for V1 interop
//
if (value)
{
_v1RasterOperation = DrawingAttributeSerializer.RasterOperationMaskPen;
}
else
{
_v1RasterOperation = DrawingAttributeSerializer.RasterOperationDefaultV1;
}
}
}
#region Extended Properties
///
/// Allows addition of objects to the EPC
///
///
///
public void AddPropertyData(Guid propertyDataId, object propertyData)
{
DrawingAttributes.ValidateStylusTipTransform(propertyDataId, propertyData);
SetExtendedPropertyBackedProperty(propertyDataId, propertyData);
}
///
/// Allows removal of objects from the EPC
///
///
public void RemovePropertyData(Guid propertyDataId)
{
this.ExtendedProperties.Remove(propertyDataId);
}
///
/// Allows retrieval of objects from the EPC
///
///
public object GetPropertyData(Guid propertyDataId)
{
return GetExtendedPropertyBackedProperty(propertyDataId);
}
///
/// Allows retrieval of a Array of guids that are contained in the EPC
///
public Guid[] GetPropertyDataIds()
{
return this.ExtendedProperties.GetGuidArray();
}
///
/// Allows check of containment of objects to the EPC
///
///
public bool ContainsPropertyData(Guid propertyDataId)
{
return this.ExtendedProperties.Contains(propertyDataId);
}
///
/// ExtendedProperties
///
internal ExtendedPropertyCollection ExtendedProperties
{
get
{
return _extendedProperties;
}
}
///
/// Returns a copy of the EPC
///
internal ExtendedPropertyCollection CopyPropertyData()
{
return this.ExtendedProperties.Clone();
}
#endregion
#endregion
#region Internal Properties
///
/// StylusShape
///
internal StylusShape StylusShape
{
get
{
StylusShape s;
if (this.StylusTip == StylusTip.Rectangle)
{
s = new RectangleStylusShape(this.Width, this.Height);
}
else
{
s = new EllipseStylusShape(this.Width, this.Height);
}
s.Transform = StylusTipTransform;
return s;
}
}
///
/// Sets the Fitting error for this drawing attributes
///
internal int FittingError
{
get
{
if (!_extendedProperties.Contains(KnownIds.CurveFittingError))
{
return 0;
}
else
{
return (int)_extendedProperties[KnownIds.CurveFittingError];
}
}
set
{
_extendedProperties[KnownIds.CurveFittingError] = value;
}
}
///
/// Sets the Fitting error for this drawing attributes
///
internal DrawingFlags DrawingFlags
{
get
{
return (DrawingFlags)GetExtendedPropertyBackedProperty(KnownIds.DrawingFlags);
}
set
{
//no need to raise change events, they will bubble up from the EPC
//underneath us
SetExtendedPropertyBackedProperty(KnownIds.DrawingFlags, value);
}
}
///
/// we need to preserve this for round tripping
///
///
internal uint RasterOperation
{
get
{
return _v1RasterOperation;
}
set
{
_v1RasterOperation = value;
}
}
///
/// When we load ISF from V1 if width is set and height is not
/// and PenTip is Circle, we need to set height to the same as width
/// or else we'll render different as an Ellipse. We use this flag to
/// preserve state for round tripping.
///
internal bool HeightChangedForCompatabity
{
get { return _heightChangedForCompatabity; }
set { _heightChangedForCompatabity = value; }
}
#endregion
//-----------------------------------------------------
//
// INotifyPropertyChanged Interface
//
//-----------------------------------------------------
#region INotifyPropertyChanged Interface
///
/// INotifyPropertyChanged.PropertyChanged event
///
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { _propertyChanged += value; }
remove { _propertyChanged -= value; }
}
#endregion INotifyPropertyChanged Interface
#region Methods
#region Object overrides
// NTRAID#T2-23041-2003/10/01-[....]: SPECISSUE: What should ExtendedPropertyCollection.GetHashCode return?
/// Retrieve an integer-based value for using ExtendedPropertyCollection
/// objects in a hash table as keys
public override int GetHashCode()
{
return base.GetHashCode();
}
/// Overload of the Equals method which determines if two DrawingAttributes
/// objects contain the same drawing attributes
public override bool Equals(object o)
{
if (o == null || o.GetType() != this.GetType())
{
return false;
}
//use as and check for null instead of casting to DA to make presharp happy
DrawingAttributes that = o as DrawingAttributes;
if (that == null)
{
return false;
}
return (this._extendedProperties == that._extendedProperties);
}
/// Overload of the equality operator which determines
/// if two DrawingAttributes are equal
public static bool operator ==(DrawingAttributes first, DrawingAttributes second)
{
// compare the GC ptrs for the obvious reference equality
if (((object)first == null && (object)second == null) ||
((object)first == (object)second))
{
return true;
}
// otherwise, if one of the ptrs are null, but not the other then return false
else if ((object)first == null || (object)second == null)
{
return false;
}
// finally use the full `blown value-style comparison against the collection contents
return first.Equals(second);
}
/// Overload of the not equals operator to determine if two
/// DrawingAttributes are different
public static bool operator !=(DrawingAttributes first, DrawingAttributes second)
{
return !(first == second);
}
#endregion
///
/// Copies the DrawingAttributes
///
/// Deep copy of the DrawingAttributes
///
public virtual DrawingAttributes Clone()
{
//
// use MemberwiseClone, which will instance the most derived type
// We use this instead of Activator.CreateInstance because it does not
// require ReflectionPermission. One thing to note, all references
// are shared, including event delegates, so we need to set those to null
//
DrawingAttributes clone = (DrawingAttributes)this.MemberwiseClone();
//
// null the delegates in the cloned DrawingAttributes
//
clone.AttributeChanged = null;
clone.PropertyDataChanged = null;
//make a copy of the epc , set up listeners
clone._extendedProperties = _extendedProperties.Clone();
clone.Initialize();
//don't need to clone these, it is a value type
//and is copied by MemberwiseClone
//_v1RasterOperation
//_heightChangedForCompatabity
return clone;
}
#endregion
#region Events
///
/// Event fired whenever a DrawingAttribute is modified
///
public event PropertyDataChangedEventHandler AttributeChanged;
///
/// Method called when a change occurs to any DrawingAttribute
///
/// The change information for the DrawingAttribute that was modified
protected virtual void OnAttributeChanged(PropertyDataChangedEventArgs e)
{
if (null == e)
{
throw new ArgumentNullException("e", SR.Get(SRID.EventArgIsNull));
}
try
{
PrivateNotifyPropertyChanged(e);
}
finally
{
if ( this.AttributeChanged != null )
{
this.AttributeChanged(this, e);
}
}
}
///
/// Event fired whenever a DrawingAttribute is modified
///
public event PropertyDataChangedEventHandler PropertyDataChanged;
///
/// Method called when a change occurs to any PropertyData
///
/// The change information for the PropertyData that was modified
protected virtual void OnPropertyDataChanged(PropertyDataChangedEventArgs e)
{
if (null == e)
{
throw new ArgumentNullException("e", SR.Get(SRID.EventArgIsNull));
}
if (this.PropertyDataChanged != null)
{
this.PropertyDataChanged(this, e);
}
}
#endregion
#region Protected Methods
///
/// Method called when a property change occurs to DrawingAttribute
///
/// The EventArgs specifying the name of the changed property.
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if ( _propertyChanged != null )
{
_propertyChanged(this, e);
}
}
#endregion Protected Methods
#region Private Methods
///
/// Simple helper method used to determine if a guid
/// from an ExtendedProperty is used as the backing store
/// of a DrawingAttribute
///
///
///
internal static object GetDefaultDrawingAttributeValue(Guid id)
{
if (KnownIds.Color == id)
{
return Colors.Black;
}
if (KnownIds.StylusWidth == id)
{
return DrawingAttributes.DefaultWidth;
}
if (KnownIds.StylusTip == id)
{
return StylusTip.Ellipse;
}
if (KnownIds.DrawingFlags == id)
{
//note that in this implementation, FitToCurve is false by default
return DrawingFlags.AntiAliased;
}
if (KnownIds.StylusHeight == id)
{
return DrawingAttributes.DefaultHeight;
}
if (KnownIds.StylusTipTransform == id)
{
return Matrix.Identity;
}
if (KnownIds.IsHighlighter == id)
{
return false;
}
// this is a valid case
// as this helper method is used not only to
// get the default value, but also to see if
// the Guid is a drawing attribute value
return null;
}
internal static void ValidateStylusTipTransform(Guid propertyDataId, object propertyData)
{
// NTRAID#WINOS-1136720-2005/06/22-XIAOTU:
// Calling AddPropertyData(KnownIds.StylusTipTransform, "d") does not throw an ArgumentException.
// ExtendedPropertySerializer.Validate take a string as a valid type since StylusTipTransform
// gets serialized as a String, but at runtime is a Matrix
if (propertyData == null)
{
throw new ArgumentNullException("propertyData");
}
else if (propertyDataId == KnownIds.StylusTipTransform)
{
// StylusTipTransform gets serialized as a String, but at runtime is a Matrix
Type t = propertyData.GetType();
if (t == typeof(String))
{
throw new ArgumentException(SR.Get(SRID.InvalidValueType, typeof(Matrix)), "propertyData");
}
}
}
///
/// Simple helper method used to determine if a guid
/// needs to be removed from the ExtendedPropertyCollection in ISF
/// before serializing
///
///
///
internal static bool RemoveIdFromExtendedProperties(Guid id)
{
if (KnownIds.Color == id ||
KnownIds.Transparency == id ||
KnownIds.StylusWidth == id ||
KnownIds.DrawingFlags == id ||
KnownIds.StylusHeight == id ||
KnownIds.CurveFittingError == id )
{
return true;
}
return false;
}
///
/// Returns true if two DrawingAttributes lead to the same PathGeometry.
///
internal static bool GeometricallyEqual(DrawingAttributes left, DrawingAttributes right)
{
// Optimization case:
// must correspond to the same path geometry if they refer to the same instance.
if (Object.ReferenceEquals(left, right))
{
return true;
}
if (left.StylusTip == right.StylusTip &&
left.StylusTipTransform == right.StylusTipTransform &&
DoubleUtil.AreClose(left.Width, right.Width) &&
DoubleUtil.AreClose(left.Height, right.Height) &&
left.DrawingFlags == right.DrawingFlags /*contains IgnorePressure / FitToCurve*/)
{
return true;
}
return false;
}
///
/// Returns true if the guid passed in has impact on geometry of the stroke
///
internal static bool IsGeometricalDaGuid(Guid guid)
{
// Assert it is a DA guid
System.Diagnostics.Debug.Assert(null != DrawingAttributes.GetDefaultDrawingAttributeValue(guid));
if (guid == KnownIds.StylusHeight || guid == KnownIds.StylusWidth ||
guid == KnownIds.StylusTipTransform || guid == KnownIds.StylusTip ||
guid == KnownIds.DrawingFlags)
{
return true;
}
return false;
}
///
/// Whenever the base class fires the generic ExtendedPropertiesChanged
/// event, we need to fire the DrawingAttributesChanged event also.
///
/// Should be 'this' object
/// The custom attributes that changed
private void ExtendedPropertiesChanged_EventForwarder(object sender, ExtendedPropertiesChangedEventArgs args)
{
System.Diagnostics.Debug.Assert(sender != null);
System.Diagnostics.Debug.Assert(args != null);
//see if the EP that changed is a drawingattribute
if (args.NewProperty == null)
{
//a property was removed, see if it is a drawing attribute property
object defaultValueIfDrawingAttribute
= DrawingAttributes.GetDefaultDrawingAttributeValue(args.OldProperty.Id);
if (defaultValueIfDrawingAttribute != null)
{
ExtendedProperty newProperty =
new ExtendedProperty( args.OldProperty.Id,
defaultValueIfDrawingAttribute);
//this is a da guid
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.OldProperty.Id,
newProperty.Value, //the property
args.OldProperty.Value);//previous value
this.OnAttributeChanged(dargs);
}
else
{
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.OldProperty.Id,
null, //the property
args.OldProperty.Value);//previous value
this.OnPropertyDataChanged(dargs);
}
}
else if (args.OldProperty == null)
{
//a property was added, see if it is a drawing attribute property
object defaultValueIfDrawingAttribute
= DrawingAttributes.GetDefaultDrawingAttributeValue(args.NewProperty.Id);
if (defaultValueIfDrawingAttribute != null)
{
if (!defaultValueIfDrawingAttribute.Equals(args.NewProperty.Value))
{
//this is a da guid
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.NewProperty.Id,
args.NewProperty.Value, //the property
defaultValueIfDrawingAttribute); //previous value
this.OnAttributeChanged(dargs);
}
}
else
{
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs(args.NewProperty.Id,
args.NewProperty.Value, //the property
null); //previous value
this.OnPropertyDataChanged(dargs);
}
}
else
{
//something was modified, see if it is a drawing attribute property
object defaultValueIfDrawingAttribute
= DrawingAttributes.GetDefaultDrawingAttributeValue(args.NewProperty.Id);
if (defaultValueIfDrawingAttribute != null)
{
//
// we only raise DA changed when the value actually changes
//
if (!args.NewProperty.Value.Equals(args.OldProperty.Value))
{
//this is a da guid
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.NewProperty.Id,
args.NewProperty.Value, //the da
args.OldProperty.Value);//old value
this.OnAttributeChanged(dargs);
}
}
else
{
if (!args.NewProperty.Value.Equals(args.OldProperty.Value))
{
PropertyDataChangedEventArgs dargs =
new PropertyDataChangedEventArgs( args.NewProperty.Id,
args.NewProperty.Value,
args.OldProperty.Value);//old value
this.OnPropertyDataChanged(dargs);
}
}
}
}
///
/// All DrawingAttributes are backed by an ExtendedProperty
/// this is a simple helper to set a property
///
/// id
/// value
private void SetExtendedPropertyBackedProperty(Guid id, object value)
{
if (_extendedProperties.Contains(id))
{
//
// check to see if we're setting the property back
// to a default value. If we are we should remove it from
// the EPC
//
object defaultValue = DrawingAttributes.GetDefaultDrawingAttributeValue(id);
if (defaultValue != null)
{
if (defaultValue.Equals(value))
{
_extendedProperties.Remove(id);
return;
}
}
//
// we're setting a non-default value on a EP that
// already exists, check for equality before we do
// so we don't raise unnecessary EPC changed events
//
object o = GetExtendedPropertyBackedProperty(id);
if (!o.Equals(value))
{
_extendedProperties[id] = value;
}
}
else
{
//
// make sure we're not setting a default value of the guid
// there is no need to do this
//
object defaultValue = DrawingAttributes.GetDefaultDrawingAttributeValue(id);
if (defaultValue == null || !defaultValue.Equals(value))
{
_extendedProperties[id] = value;
}
}
}
///
/// All DrawingAttributes are backed by an ExtendedProperty
/// this is a simple helper to set a property
///
/// id
///
private object GetExtendedPropertyBackedProperty(Guid id)
{
if (!_extendedProperties.Contains(id))
{
if (null != DrawingAttributes.GetDefaultDrawingAttributeValue(id))
{
return DrawingAttributes.GetDefaultDrawingAttributeValue(id);
}
throw new ArgumentException(SR.Get(SRID.EPGuidNotFound), "id");
}
else
{
return _extendedProperties[id];
}
}
///
/// A help method which fires INotifyPropertyChanged.PropertyChanged event
///
///
private void PrivateNotifyPropertyChanged(PropertyDataChangedEventArgs e)
{
if ( e.PropertyGuid == KnownIds.Color)
{
OnPropertyChanged("Color");
}
else if ( e.PropertyGuid == KnownIds.StylusTip)
{
OnPropertyChanged("StylusTip");
}
else if ( e.PropertyGuid == KnownIds.StylusTipTransform)
{
OnPropertyChanged("StylusTipTransform");
}
else if ( e.PropertyGuid == KnownIds.StylusHeight)
{
OnPropertyChanged("Height");
}
else if ( e.PropertyGuid == KnownIds.StylusWidth)
{
OnPropertyChanged("Width");
}
else if ( e.PropertyGuid == KnownIds.IsHighlighter)
{
OnPropertyChanged("IsHighlighter");
}
else if ( e.PropertyGuid == KnownIds.DrawingFlags )
{
DrawingFlags changedBits = ( ( (DrawingFlags)e.PreviousValue ) ^ ( (DrawingFlags)e.NewValue ) );
// NOTICE-2006/01/20-WAYNEZEN,
// If someone changes FitToCurve and IgnorePressure simultaneously via AddPropertyData/RemovePropertyData,
// we will fire both OnPropertyChangeds in advance the order of the values.
if ( (changedBits & DrawingFlags.FitToCurve) != 0 )
{
OnPropertyChanged("FitToCurve");
}
if ( (changedBits & DrawingFlags.IgnorePressure) != 0 )
{
OnPropertyChanged("IgnorePressure");
}
}
}
private void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Private Fields
// The private PropertyChanged event
private PropertyChangedEventHandler _propertyChanged;
private ExtendedPropertyCollection _extendedProperties;
private uint _v1RasterOperation = DrawingAttributeSerializer.RasterOperationDefaultV1;
private bool _heightChangedForCompatabity = false;
///
/// Statics
///
internal static readonly float StylusPrecision = 1000.0f;
internal static readonly double DefaultWidth = 2.0031496062992127;
internal static readonly double DefaultHeight = 2.0031496062992127;
#endregion
///
/// Mininum acceptable stylus tip height, corresponds to 0.001 in V1
///
/// corresponds to 0.001 in V1 (0.001 / (2540/96))
public static readonly double MinHeight = 0.00003779527559055120;
///
/// Minimum acceptable stylus tip width
///
/// corresponds to 0.001 in V1 (0.001 / (2540/96))
public static readonly double MinWidth = 0.00003779527559055120;
///
/// Maximum acceptable stylus tip height.
///
/// corresponds to 4294967 in V1 (4294967 / (2540/96))
public static readonly double MaxHeight = 162329.4614173230;
///
/// Maximum acceptable stylus tip width.
///
/// corresponds to 4294967 in V1 (4294967 / (2540/96))
public static readonly double MaxWidth = 162329.4614173230;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FormClosingEvent.cs
- DateTimeOffsetConverter.cs
- RealProxy.cs
- WmlTextViewAdapter.cs
- BitmapEffectGroup.cs
- CollectionChangeEventArgs.cs
- TargetConverter.cs
- TextTreeFixupNode.cs
- OleDbErrorCollection.cs
- InstancePersistenceCommand.cs
- SrgsElement.cs
- LoginNameDesigner.cs
- SqlInternalConnection.cs
- FixedDocumentSequencePaginator.cs
- SID.cs
- UdpDiscoveryMessageFilter.cs
- MissingSatelliteAssemblyException.cs
- XamlVector3DCollectionSerializer.cs
- ObjectStateEntryBaseUpdatableDataRecord.cs
- WmlTextViewAdapter.cs
- ListGeneralPage.cs
- RouteValueDictionary.cs
- FileDetails.cs
- WebPartDisplayMode.cs
- NativeObjectSecurity.cs
- MissingSatelliteAssemblyException.cs
- EdmPropertyAttribute.cs
- ToolBarButton.cs
- Convert.cs
- DbConnectionPoolGroup.cs
- MetaModel.cs
- StringValueConverter.cs
- InheritanceRules.cs
- TagMapCollection.cs
- TextServicesCompartmentEventSink.cs
- ZeroOpNode.cs
- EncoderBestFitFallback.cs
- Path.cs
- Helper.cs
- XmlHelper.cs
- AlphabeticalEnumConverter.cs
- AppDomainAttributes.cs
- TypeContext.cs
- TCPListener.cs
- DomainConstraint.cs
- ListSortDescription.cs
- PingOptions.cs
- ValidatorCollection.cs
- CqlLexer.cs
- FixedTextView.cs
- WebPartMenuStyle.cs
- SpeechEvent.cs
- GridViewRowPresenter.cs
- _ProxyRegBlob.cs
- ImageIndexConverter.cs
- RectangleHotSpot.cs
- StringSource.cs
- TrackingLocation.cs
- XmlSchemaAnnotated.cs
- SafeArrayTypeMismatchException.cs
- TextBoxAutomationPeer.cs
- Rect.cs
- SimpleFieldTemplateUserControl.cs
- WinEventQueueItem.cs
- TextRunCacheImp.cs
- BoundPropertyEntry.cs
- FontFaceLayoutInfo.cs
- SpellCheck.cs
- NotSupportedException.cs
- HttpClientCertificate.cs
- Quaternion.cs
- Matrix3DConverter.cs
- ConfigurationPropertyCollection.cs
- InvalidOperationException.cs
- BinarySerializer.cs
- WebEvents.cs
- ContractCodeDomInfo.cs
- TokenBasedSet.cs
- ChangeProcessor.cs
- SerialErrors.cs
- Helper.cs
- DataGridViewRowHeightInfoPushedEventArgs.cs
- PersonalizationState.cs
- InvalidFilterCriteriaException.cs
- SqlStream.cs
- DummyDataSource.cs
- ConversionContext.cs
- InputScopeAttribute.cs
- ApplicationServiceManager.cs
- TypeConverterMarkupExtension.cs
- XmlSchemaElement.cs
- ParseChildrenAsPropertiesAttribute.cs
- XsltQilFactory.cs
- NTAccount.cs
- TextEditorCopyPaste.cs
- _LocalDataStore.cs
- MemberRelationshipService.cs
- HMACRIPEMD160.cs
- GACIdentityPermission.cs
- XmlSchemaSimpleTypeList.cs