Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Shapes / Shape.cs / 1 / Shape.cs
//---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // Description: Shape element is a base class for shapes like Path, // Rectangle, GlyphRun etc. // // History: // // 06/02/2003 : mleonov - created. // 07/29/2004 : timothyc - Added ValidateValueCallback for enumeration // properties // //--------------------------------------------------------------------------- using System.Diagnostics; using System.Windows.Threading; using System.Windows; using System.Windows.Media; using System.ComponentModel; using MS.Internal; using MS.Internal.PresentationFramework; using System; namespace System.Windows.Shapes { ////// Shape is a base class for shape elements /// [Localizability(LocalizationCategory.None, Readability=Readability.Unreadable)] public abstract class Shape : FrameworkElement { #region Constructors ////// Shape Constructor /// protected Shape() { } #endregion #region Properties ////// DependencyProperty for the Stretch property. /// public static readonly DependencyProperty StretchProperty = DependencyProperty.Register( "Stretch", // Property name typeof(Stretch), // Property type typeof(Shape), // Property owner new FrameworkPropertyMetadata(Stretch.None, FrameworkPropertyMetadataOptions.AffectsArrange)); ////// The Stretch property determines how the shape may be stretched to accommodate shape size /// public Stretch Stretch { get { return (Stretch)GetValue(StretchProperty); } set { SetValue(StretchProperty, value); } } ////// The RenderedGeometry property returns the final rendered geometry /// public virtual Geometry RenderedGeometry { get { EnsureRenderedGeometry(); Geometry geometry = _renderedGeometry.CloneCurrentValue(); if (geometry == null || geometry == Geometry.Empty) { return Geometry.Empty; } // We need to return a frozen copy if (Object.ReferenceEquals(geometry, _renderedGeometry)) { // geometry is a reference to _renderedGeometry, so we need to copy geometry = geometry.Clone(); geometry.Freeze(); } return geometry; } } ////// Return the transformation applied to the geometry before rendering /// public virtual Transform GeometryTransform { get { BoxedMatrix stretchMatrix = StretchMatrixField.GetValue(this); if (stretchMatrix == null) { return Transform.Identity; } else { return new MatrixTransform(stretchMatrix.Value); } } } private static void OnPenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // Called when any of the Stroke properties is invalidated. // That means that the cached pen should be recalculated. ((Shape)d)._pen = null; } ////// Fill property /// [CommonDependencyProperty] public static readonly DependencyProperty FillProperty = DependencyProperty.Register( "Fill", typeof(Brush), typeof(Shape), new FrameworkPropertyMetadata( (Brush) null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); ////// Fill property /// public Brush Fill { get { return (Brush) GetValue(FillProperty); } set { SetValue(FillProperty, value); } } ////// Stroke property /// [CommonDependencyProperty] public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register( "Stroke", typeof(Brush), typeof(Shape), new FrameworkPropertyMetadata( (Brush) null, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, new PropertyChangedCallback(OnPenChanged))); ////// Stroke property /// public Brush Stroke { get { return (Brush) GetValue(StrokeProperty); } set { SetValue(StrokeProperty, value); } } ////// StrokeThickness property /// [CommonDependencyProperty] public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register( "StrokeThickness", typeof(double), typeof(Shape), new FrameworkPropertyMetadata( 1.0d, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged))); ////// StrokeThickness property /// [TypeConverter(typeof(LengthConverter))] public double StrokeThickness { get { return (double) GetValue(StrokeThicknessProperty); } set { SetValue(StrokeThicknessProperty, value); } } ////// StrokeStartLineCap property /// public static readonly DependencyProperty StrokeStartLineCapProperty = DependencyProperty.Register( "StrokeStartLineCap", typeof(PenLineCap), typeof(Shape), new FrameworkPropertyMetadata( PenLineCap.Flat, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged)), new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid)); ////// StrokeStartLineCap property /// public PenLineCap StrokeStartLineCap { get { return (PenLineCap) GetValue(StrokeStartLineCapProperty); } set { SetValue(StrokeStartLineCapProperty, value); } } ////// StrokeEndLineCap property /// public static readonly DependencyProperty StrokeEndLineCapProperty = DependencyProperty.Register( "StrokeEndLineCap", typeof(PenLineCap), typeof(Shape), new FrameworkPropertyMetadata( PenLineCap.Flat, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged)), new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid)); ////// StrokeEndLineCap property /// public PenLineCap StrokeEndLineCap { get { return (PenLineCap) GetValue(StrokeEndLineCapProperty); } set { SetValue(StrokeEndLineCapProperty, value); } } ////// StrokeDashCap property /// public static readonly DependencyProperty StrokeDashCapProperty = DependencyProperty.Register( "StrokeDashCap", typeof(PenLineCap), typeof(Shape), new FrameworkPropertyMetadata( PenLineCap.Flat, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged)), new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid)); ////// StrokeDashCap property /// public PenLineCap StrokeDashCap { get { return (PenLineCap) GetValue(StrokeDashCapProperty); } set { SetValue(StrokeDashCapProperty, value); } } ////// StrokeLineJoin property /// public static readonly DependencyProperty StrokeLineJoinProperty = DependencyProperty.Register( "StrokeLineJoin", typeof(PenLineJoin), typeof(Shape), new FrameworkPropertyMetadata( PenLineJoin.Miter, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged)), new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineJoinValid)); ////// StrokeLineJoin property /// public PenLineJoin StrokeLineJoin { get { return (PenLineJoin) GetValue(StrokeLineJoinProperty); } set { SetValue(StrokeLineJoinProperty, value); } } ////// StrokeMiterLimit property /// public static readonly DependencyProperty StrokeMiterLimitProperty = DependencyProperty.Register( "StrokeMiterLimit", typeof(double), typeof(Shape), new FrameworkPropertyMetadata( 10.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged))); ////// StrokeMiterLimit property /// public double StrokeMiterLimit { get { return (double) GetValue(StrokeMiterLimitProperty); } set { SetValue(StrokeMiterLimitProperty, value); } } ////// StrokeDashOffset property /// public static readonly DependencyProperty StrokeDashOffsetProperty = DependencyProperty.Register( "StrokeDashOffset", typeof(double), typeof(Shape), new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged))); ////// StrokeDashOffset property /// public double StrokeDashOffset { get { return (double) GetValue(StrokeDashOffsetProperty); } set { SetValue(StrokeDashOffsetProperty, value); } } ////// StrokeDashArray property /// public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register( "StrokeDashArray", typeof(DoubleCollection), typeof(Shape), new FrameworkPropertyMetadata( new FreezableDefaultValueFactory(DoubleCollection.Empty), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged))); ////// StrokeDashArray property /// public DoubleCollection StrokeDashArray { get { return (DoubleCollection) GetValue(StrokeDashArrayProperty); } set { SetValue(StrokeDashArrayProperty, value); } } #endregion #region Protected Methods ////// Updates DesiredSize of the shape. Called by parent UIElement during is the first pass of layout. /// /// Constraint size is an "upper limit" that should not exceed. ///Shape's desired size. protected override Size MeasureOverride(Size constraint) { CacheDefiningGeometry(); Size newSize; Stretch mode = Stretch; if (mode == Stretch.None) { newSize = GetNaturalSize(); } else { newSize = GetStretchedRenderSize(mode, GetStrokeThickness(), constraint, GetDefiningGeometryBounds()); } if (SizeIsInvalidOrEmpty(newSize)) { // We've encountered a numerical error. Don't draw anything. newSize = new Size(0,0); _renderedGeometry = Geometry.Empty; } return newSize; } ////// Compute the rendered geometry and the stretching transform. /// protected override Size ArrangeOverride(Size finalSize) { Size newSize; Stretch mode = Stretch; if (mode == Stretch.None) { StretchMatrixField.ClearValue(this); ResetRenderedGeometry(); newSize = finalSize; } else { newSize = GetStretchedRenderSizeAndSetStretchMatrix( mode, GetStrokeThickness(), finalSize, GetDefiningGeometryBounds()); } if (SizeIsInvalidOrEmpty(newSize)) { // We've encountered a numerical error. Don't draw anything. newSize = new Size(0,0); _renderedGeometry = Geometry.Empty; } return newSize; } ////// Render callback. /// protected override void OnRender(DrawingContext drawingContext) { EnsureRenderedGeometry(); if (_renderedGeometry != Geometry.Empty) { drawingContext.DrawGeometry(Fill, GetPen(), _renderedGeometry); } } #endregion #region Protected Properties ////// Get the geometry that defines this shape /// protected abstract Geometry DefiningGeometry { get; } #endregion Protected Properties #region Internal Methods internal bool SizeIsInvalidOrEmpty(Size size) { return (DoubleUtil.IsNaN(size.Width) || DoubleUtil.IsNaN(size.Height) || size.IsEmpty); } internal bool IsPenNoOp { get { double strokeThickness = StrokeThickness; return (Stroke == null) || DoubleUtil.IsNaN(strokeThickness) || DoubleUtil.IsZero(strokeThickness); } } internal double GetStrokeThickness() { if (IsPenNoOp) { return 0; } else { return Math.Abs(StrokeThickness); } } internal Pen GetPen() { if (IsPenNoOp) { return null; } if (_pen == null) { double thickness = 0.0; double strokeThickness = StrokeThickness; thickness = Math.Abs(strokeThickness); // This pen is internal to the system and // must not participate in freezable treeness _pen = new Pen(); _pen.CanBeInheritanceContext = false; _pen.Thickness = thickness; _pen.Brush = Stroke; _pen.StartLineCap = StrokeStartLineCap; _pen.EndLineCap = StrokeEndLineCap; _pen.DashCap = StrokeDashCap; _pen.LineJoin = StrokeLineJoin; _pen.MiterLimit = StrokeMiterLimit; // StrokeDashArray is usually going to be its default value and GetValue // on a mutable default has a per-instance cost associated with it so we'll // try to avoid caching the default value DoubleCollection strokeDashArray = null; bool hasModifiers; if (GetValueSource(StrokeDashArrayProperty, null, out hasModifiers) != BaseValueSourceInternal.Default || hasModifiers) { strokeDashArray = StrokeDashArray; } // Avoid creating the DashStyle if we can double strokeDashOffset = StrokeDashOffset; if (strokeDashArray != null || strokeDashOffset != 0.0) { _pen.DashStyle = new DashStyle(strokeDashArray, strokeDashOffset); } } return _pen; } // Double verification helpers. Property system will verify type for us; we only need to verify the value. internal static bool IsDoubleFiniteNonNegative(object o) { double d = (double)o; return !(Double.IsInfinity(d) || DoubleUtil.IsNaN(d) || d < 0.0); } internal static bool IsDoubleFinite(object o) { double d = (double)o; return !(Double.IsInfinity(d) || DoubleUtil.IsNaN(d)); } internal static bool IsDoubleFiniteOrNaN(object o) { double d = (double)o; return !(Double.IsInfinity(d)); } internal virtual void CacheDefiningGeometry() {} internal Size GetStretchedRenderSize(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds) { double xScale, yScale, dX, dY; Size renderSize; GetStretchMetrics(mode, strokeThickness, availableSize, geometryBounds, out xScale, out yScale, out dX, out dY, out renderSize); return renderSize; } internal Size GetStretchedRenderSizeAndSetStretchMatrix(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds) { double xScale, yScale, dX, dY; Size renderSize; GetStretchMetrics(mode, strokeThickness, availableSize, geometryBounds, out xScale, out yScale, out dX, out dY, out renderSize); // Construct the matrix Matrix stretchMatrix = Matrix.Identity; stretchMatrix.ScaleAt(xScale, yScale, geometryBounds.Location.X, geometryBounds.Location.Y); stretchMatrix.Translate(dX, dY); StretchMatrixField.SetValue(this, new BoxedMatrix(stretchMatrix)); ResetRenderedGeometry(); return renderSize; } internal void ResetRenderedGeometry() { // reset rendered geometry _renderedGeometry = null; } internal void GetStretchMetrics(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds, out double xScale, out double yScale, out double dX, out double dY, out Size stretchedSize) { if (!geometryBounds.IsEmpty) { double margin = strokeThickness / 2; bool hasThinDimension = false; // Initialization for mode == Fill xScale = Math.Max(availableSize.Width - strokeThickness, 0); yScale = Math.Max(availableSize.Height - strokeThickness, 0); dX = margin - geometryBounds.Left; dY = margin - geometryBounds.Top; // Compute the scale factors from the geometry to the size. // The scale factors are ratios, and they have already been initialize to the numerators. // To prevent fp overflow, we need to make sure that numerator / denomiator < limit; // To do that without actually deviding, we check that denominator > numerator / limit. // We take 1/epsilon as the limit, so the check is denominator > numerator * epsilon if (geometryBounds.Width > xScale * Double.Epsilon) { xScale /= geometryBounds.Width; } else { xScale = 1; hasThinDimension = true; } if (geometryBounds.Height > yScale * Double.Epsilon) { yScale /= geometryBounds.Height; } else { yScale = 1; hasThinDimension = true; } // Because this case was handled by the caller Debug.Assert(mode != Stretch.None); // We are initialized for Fill, but for the other modes // If one of our dimensions is thin, uniform stretches are // meaningless, so we treat the stretch as fill. if (mode != Stretch.Fill && !hasThinDimension) { if (mode == Stretch.Uniform) { if (yScale > xScale) { // Resize to fit the size's width yScale = xScale; } else // if xScale >= yScale { // Resize to fit the size's height xScale = yScale; } } else { Debug.Assert(mode == Stretch.UniformToFill); if (xScale > yScale) { // Resize to fill the size vertically, spilling out horizontally yScale = xScale; } else // if yScale >= xScale { // Resize to fill the size horizontally, spilling out vertically xScale = yScale; } } } stretchedSize = new Size(geometryBounds.Width * xScale + strokeThickness, geometryBounds.Height * yScale + strokeThickness); } else { xScale = yScale = 1; dX = dY = 0; stretchedSize = new Size(0,0); } } ////// Get the natural size of the geometry that defines this shape /// internal virtual Size GetNaturalSize() { Geometry geometry = DefiningGeometry; Debug.Assert(geometry != null); // // For the purposes of computing layout size, don't consider dashing. This will give us // slightly different bounds, but the computation will be faster and more stable. // // NOTE: If GetPen() is ever made public, we will need to change this logic so the user // isn't affected by our surreptitious change of DashStyle. // Pen pen = GetPen(); DashStyle style = null; if (pen != null) { style = pen.DashStyle; if (style != null) { pen.DashStyle = null; } } Rect bounds = geometry.GetRenderBounds(pen); if (style != null) { pen.DashStyle = style; } return new Size(Math.Max(bounds.Right, 0), Math.Max(bounds.Bottom, 0)); } ////// Get the bonds of the geometry that defines this shape /// internal virtual Rect GetDefiningGeometryBounds() { Geometry geometry = DefiningGeometry; Debug.Assert(geometry != null); return geometry.Bounds; } internal void EnsureRenderedGeometry() { if (_renderedGeometry == null) { _renderedGeometry = DefiningGeometry; Debug.Assert(_renderedGeometry != null); if (Stretch != Stretch.None) { Geometry currentValue = _renderedGeometry.CloneCurrentValue(); if (Object.ReferenceEquals(_renderedGeometry, currentValue)) { _renderedGeometry = currentValue.Clone(); } else { _renderedGeometry = currentValue; } Transform renderedTransform = _renderedGeometry.Transform; BoxedMatrix boxedStretchMatrix = StretchMatrixField.GetValue(this); Matrix stretchMatrix = (boxedStretchMatrix == null) ? Matrix.Identity : boxedStretchMatrix.Value; if (renderedTransform == null || renderedTransform.IsIdentity) { _renderedGeometry.Transform = new MatrixTransform(stretchMatrix); } else { _renderedGeometry.Transform = new MatrixTransform(renderedTransform.Value * stretchMatrix); } } } } #endregion Internal Methods #region Private Fields private Pen _pen = null; private Geometry _renderedGeometry = Geometry.Empty; private static UncommonFieldStretchMatrixField = new UncommonField (null); #endregion Private Fields } internal class BoxedMatrix { public BoxedMatrix(Matrix value) { Value = value; } public Matrix Value; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // Description: Shape element is a base class for shapes like Path, // Rectangle, GlyphRun etc. // // History: // // 06/02/2003 : mleonov - created. // 07/29/2004 : timothyc - Added ValidateValueCallback for enumeration // properties // //--------------------------------------------------------------------------- using System.Diagnostics; using System.Windows.Threading; using System.Windows; using System.Windows.Media; using System.ComponentModel; using MS.Internal; using MS.Internal.PresentationFramework; using System; namespace System.Windows.Shapes { /// /// Shape is a base class for shape elements /// [Localizability(LocalizationCategory.None, Readability=Readability.Unreadable)] public abstract class Shape : FrameworkElement { #region Constructors ////// Shape Constructor /// protected Shape() { } #endregion #region Properties ////// DependencyProperty for the Stretch property. /// public static readonly DependencyProperty StretchProperty = DependencyProperty.Register( "Stretch", // Property name typeof(Stretch), // Property type typeof(Shape), // Property owner new FrameworkPropertyMetadata(Stretch.None, FrameworkPropertyMetadataOptions.AffectsArrange)); ////// The Stretch property determines how the shape may be stretched to accommodate shape size /// public Stretch Stretch { get { return (Stretch)GetValue(StretchProperty); } set { SetValue(StretchProperty, value); } } ////// The RenderedGeometry property returns the final rendered geometry /// public virtual Geometry RenderedGeometry { get { EnsureRenderedGeometry(); Geometry geometry = _renderedGeometry.CloneCurrentValue(); if (geometry == null || geometry == Geometry.Empty) { return Geometry.Empty; } // We need to return a frozen copy if (Object.ReferenceEquals(geometry, _renderedGeometry)) { // geometry is a reference to _renderedGeometry, so we need to copy geometry = geometry.Clone(); geometry.Freeze(); } return geometry; } } ////// Return the transformation applied to the geometry before rendering /// public virtual Transform GeometryTransform { get { BoxedMatrix stretchMatrix = StretchMatrixField.GetValue(this); if (stretchMatrix == null) { return Transform.Identity; } else { return new MatrixTransform(stretchMatrix.Value); } } } private static void OnPenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // Called when any of the Stroke properties is invalidated. // That means that the cached pen should be recalculated. ((Shape)d)._pen = null; } ////// Fill property /// [CommonDependencyProperty] public static readonly DependencyProperty FillProperty = DependencyProperty.Register( "Fill", typeof(Brush), typeof(Shape), new FrameworkPropertyMetadata( (Brush) null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); ////// Fill property /// public Brush Fill { get { return (Brush) GetValue(FillProperty); } set { SetValue(FillProperty, value); } } ////// Stroke property /// [CommonDependencyProperty] public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register( "Stroke", typeof(Brush), typeof(Shape), new FrameworkPropertyMetadata( (Brush) null, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, new PropertyChangedCallback(OnPenChanged))); ////// Stroke property /// public Brush Stroke { get { return (Brush) GetValue(StrokeProperty); } set { SetValue(StrokeProperty, value); } } ////// StrokeThickness property /// [CommonDependencyProperty] public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register( "StrokeThickness", typeof(double), typeof(Shape), new FrameworkPropertyMetadata( 1.0d, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged))); ////// StrokeThickness property /// [TypeConverter(typeof(LengthConverter))] public double StrokeThickness { get { return (double) GetValue(StrokeThicknessProperty); } set { SetValue(StrokeThicknessProperty, value); } } ////// StrokeStartLineCap property /// public static readonly DependencyProperty StrokeStartLineCapProperty = DependencyProperty.Register( "StrokeStartLineCap", typeof(PenLineCap), typeof(Shape), new FrameworkPropertyMetadata( PenLineCap.Flat, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged)), new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid)); ////// StrokeStartLineCap property /// public PenLineCap StrokeStartLineCap { get { return (PenLineCap) GetValue(StrokeStartLineCapProperty); } set { SetValue(StrokeStartLineCapProperty, value); } } ////// StrokeEndLineCap property /// public static readonly DependencyProperty StrokeEndLineCapProperty = DependencyProperty.Register( "StrokeEndLineCap", typeof(PenLineCap), typeof(Shape), new FrameworkPropertyMetadata( PenLineCap.Flat, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged)), new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid)); ////// StrokeEndLineCap property /// public PenLineCap StrokeEndLineCap { get { return (PenLineCap) GetValue(StrokeEndLineCapProperty); } set { SetValue(StrokeEndLineCapProperty, value); } } ////// StrokeDashCap property /// public static readonly DependencyProperty StrokeDashCapProperty = DependencyProperty.Register( "StrokeDashCap", typeof(PenLineCap), typeof(Shape), new FrameworkPropertyMetadata( PenLineCap.Flat, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged)), new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineCapValid)); ////// StrokeDashCap property /// public PenLineCap StrokeDashCap { get { return (PenLineCap) GetValue(StrokeDashCapProperty); } set { SetValue(StrokeDashCapProperty, value); } } ////// StrokeLineJoin property /// public static readonly DependencyProperty StrokeLineJoinProperty = DependencyProperty.Register( "StrokeLineJoin", typeof(PenLineJoin), typeof(Shape), new FrameworkPropertyMetadata( PenLineJoin.Miter, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged)), new ValidateValueCallback(System.Windows.Media.ValidateEnums.IsPenLineJoinValid)); ////// StrokeLineJoin property /// public PenLineJoin StrokeLineJoin { get { return (PenLineJoin) GetValue(StrokeLineJoinProperty); } set { SetValue(StrokeLineJoinProperty, value); } } ////// StrokeMiterLimit property /// public static readonly DependencyProperty StrokeMiterLimitProperty = DependencyProperty.Register( "StrokeMiterLimit", typeof(double), typeof(Shape), new FrameworkPropertyMetadata( 10.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged))); ////// StrokeMiterLimit property /// public double StrokeMiterLimit { get { return (double) GetValue(StrokeMiterLimitProperty); } set { SetValue(StrokeMiterLimitProperty, value); } } ////// StrokeDashOffset property /// public static readonly DependencyProperty StrokeDashOffsetProperty = DependencyProperty.Register( "StrokeDashOffset", typeof(double), typeof(Shape), new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged))); ////// StrokeDashOffset property /// public double StrokeDashOffset { get { return (double) GetValue(StrokeDashOffsetProperty); } set { SetValue(StrokeDashOffsetProperty, value); } } ////// StrokeDashArray property /// public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register( "StrokeDashArray", typeof(DoubleCollection), typeof(Shape), new FrameworkPropertyMetadata( new FreezableDefaultValueFactory(DoubleCollection.Empty), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPenChanged))); ////// StrokeDashArray property /// public DoubleCollection StrokeDashArray { get { return (DoubleCollection) GetValue(StrokeDashArrayProperty); } set { SetValue(StrokeDashArrayProperty, value); } } #endregion #region Protected Methods ////// Updates DesiredSize of the shape. Called by parent UIElement during is the first pass of layout. /// /// Constraint size is an "upper limit" that should not exceed. ///Shape's desired size. protected override Size MeasureOverride(Size constraint) { CacheDefiningGeometry(); Size newSize; Stretch mode = Stretch; if (mode == Stretch.None) { newSize = GetNaturalSize(); } else { newSize = GetStretchedRenderSize(mode, GetStrokeThickness(), constraint, GetDefiningGeometryBounds()); } if (SizeIsInvalidOrEmpty(newSize)) { // We've encountered a numerical error. Don't draw anything. newSize = new Size(0,0); _renderedGeometry = Geometry.Empty; } return newSize; } ////// Compute the rendered geometry and the stretching transform. /// protected override Size ArrangeOverride(Size finalSize) { Size newSize; Stretch mode = Stretch; if (mode == Stretch.None) { StretchMatrixField.ClearValue(this); ResetRenderedGeometry(); newSize = finalSize; } else { newSize = GetStretchedRenderSizeAndSetStretchMatrix( mode, GetStrokeThickness(), finalSize, GetDefiningGeometryBounds()); } if (SizeIsInvalidOrEmpty(newSize)) { // We've encountered a numerical error. Don't draw anything. newSize = new Size(0,0); _renderedGeometry = Geometry.Empty; } return newSize; } ////// Render callback. /// protected override void OnRender(DrawingContext drawingContext) { EnsureRenderedGeometry(); if (_renderedGeometry != Geometry.Empty) { drawingContext.DrawGeometry(Fill, GetPen(), _renderedGeometry); } } #endregion #region Protected Properties ////// Get the geometry that defines this shape /// protected abstract Geometry DefiningGeometry { get; } #endregion Protected Properties #region Internal Methods internal bool SizeIsInvalidOrEmpty(Size size) { return (DoubleUtil.IsNaN(size.Width) || DoubleUtil.IsNaN(size.Height) || size.IsEmpty); } internal bool IsPenNoOp { get { double strokeThickness = StrokeThickness; return (Stroke == null) || DoubleUtil.IsNaN(strokeThickness) || DoubleUtil.IsZero(strokeThickness); } } internal double GetStrokeThickness() { if (IsPenNoOp) { return 0; } else { return Math.Abs(StrokeThickness); } } internal Pen GetPen() { if (IsPenNoOp) { return null; } if (_pen == null) { double thickness = 0.0; double strokeThickness = StrokeThickness; thickness = Math.Abs(strokeThickness); // This pen is internal to the system and // must not participate in freezable treeness _pen = new Pen(); _pen.CanBeInheritanceContext = false; _pen.Thickness = thickness; _pen.Brush = Stroke; _pen.StartLineCap = StrokeStartLineCap; _pen.EndLineCap = StrokeEndLineCap; _pen.DashCap = StrokeDashCap; _pen.LineJoin = StrokeLineJoin; _pen.MiterLimit = StrokeMiterLimit; // StrokeDashArray is usually going to be its default value and GetValue // on a mutable default has a per-instance cost associated with it so we'll // try to avoid caching the default value DoubleCollection strokeDashArray = null; bool hasModifiers; if (GetValueSource(StrokeDashArrayProperty, null, out hasModifiers) != BaseValueSourceInternal.Default || hasModifiers) { strokeDashArray = StrokeDashArray; } // Avoid creating the DashStyle if we can double strokeDashOffset = StrokeDashOffset; if (strokeDashArray != null || strokeDashOffset != 0.0) { _pen.DashStyle = new DashStyle(strokeDashArray, strokeDashOffset); } } return _pen; } // Double verification helpers. Property system will verify type for us; we only need to verify the value. internal static bool IsDoubleFiniteNonNegative(object o) { double d = (double)o; return !(Double.IsInfinity(d) || DoubleUtil.IsNaN(d) || d < 0.0); } internal static bool IsDoubleFinite(object o) { double d = (double)o; return !(Double.IsInfinity(d) || DoubleUtil.IsNaN(d)); } internal static bool IsDoubleFiniteOrNaN(object o) { double d = (double)o; return !(Double.IsInfinity(d)); } internal virtual void CacheDefiningGeometry() {} internal Size GetStretchedRenderSize(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds) { double xScale, yScale, dX, dY; Size renderSize; GetStretchMetrics(mode, strokeThickness, availableSize, geometryBounds, out xScale, out yScale, out dX, out dY, out renderSize); return renderSize; } internal Size GetStretchedRenderSizeAndSetStretchMatrix(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds) { double xScale, yScale, dX, dY; Size renderSize; GetStretchMetrics(mode, strokeThickness, availableSize, geometryBounds, out xScale, out yScale, out dX, out dY, out renderSize); // Construct the matrix Matrix stretchMatrix = Matrix.Identity; stretchMatrix.ScaleAt(xScale, yScale, geometryBounds.Location.X, geometryBounds.Location.Y); stretchMatrix.Translate(dX, dY); StretchMatrixField.SetValue(this, new BoxedMatrix(stretchMatrix)); ResetRenderedGeometry(); return renderSize; } internal void ResetRenderedGeometry() { // reset rendered geometry _renderedGeometry = null; } internal void GetStretchMetrics(Stretch mode, double strokeThickness, Size availableSize, Rect geometryBounds, out double xScale, out double yScale, out double dX, out double dY, out Size stretchedSize) { if (!geometryBounds.IsEmpty) { double margin = strokeThickness / 2; bool hasThinDimension = false; // Initialization for mode == Fill xScale = Math.Max(availableSize.Width - strokeThickness, 0); yScale = Math.Max(availableSize.Height - strokeThickness, 0); dX = margin - geometryBounds.Left; dY = margin - geometryBounds.Top; // Compute the scale factors from the geometry to the size. // The scale factors are ratios, and they have already been initialize to the numerators. // To prevent fp overflow, we need to make sure that numerator / denomiator < limit; // To do that without actually deviding, we check that denominator > numerator / limit. // We take 1/epsilon as the limit, so the check is denominator > numerator * epsilon if (geometryBounds.Width > xScale * Double.Epsilon) { xScale /= geometryBounds.Width; } else { xScale = 1; hasThinDimension = true; } if (geometryBounds.Height > yScale * Double.Epsilon) { yScale /= geometryBounds.Height; } else { yScale = 1; hasThinDimension = true; } // Because this case was handled by the caller Debug.Assert(mode != Stretch.None); // We are initialized for Fill, but for the other modes // If one of our dimensions is thin, uniform stretches are // meaningless, so we treat the stretch as fill. if (mode != Stretch.Fill && !hasThinDimension) { if (mode == Stretch.Uniform) { if (yScale > xScale) { // Resize to fit the size's width yScale = xScale; } else // if xScale >= yScale { // Resize to fit the size's height xScale = yScale; } } else { Debug.Assert(mode == Stretch.UniformToFill); if (xScale > yScale) { // Resize to fill the size vertically, spilling out horizontally yScale = xScale; } else // if yScale >= xScale { // Resize to fill the size horizontally, spilling out vertically xScale = yScale; } } } stretchedSize = new Size(geometryBounds.Width * xScale + strokeThickness, geometryBounds.Height * yScale + strokeThickness); } else { xScale = yScale = 1; dX = dY = 0; stretchedSize = new Size(0,0); } } ////// Get the natural size of the geometry that defines this shape /// internal virtual Size GetNaturalSize() { Geometry geometry = DefiningGeometry; Debug.Assert(geometry != null); // // For the purposes of computing layout size, don't consider dashing. This will give us // slightly different bounds, but the computation will be faster and more stable. // // NOTE: If GetPen() is ever made public, we will need to change this logic so the user // isn't affected by our surreptitious change of DashStyle. // Pen pen = GetPen(); DashStyle style = null; if (pen != null) { style = pen.DashStyle; if (style != null) { pen.DashStyle = null; } } Rect bounds = geometry.GetRenderBounds(pen); if (style != null) { pen.DashStyle = style; } return new Size(Math.Max(bounds.Right, 0), Math.Max(bounds.Bottom, 0)); } ////// Get the bonds of the geometry that defines this shape /// internal virtual Rect GetDefiningGeometryBounds() { Geometry geometry = DefiningGeometry; Debug.Assert(geometry != null); return geometry.Bounds; } internal void EnsureRenderedGeometry() { if (_renderedGeometry == null) { _renderedGeometry = DefiningGeometry; Debug.Assert(_renderedGeometry != null); if (Stretch != Stretch.None) { Geometry currentValue = _renderedGeometry.CloneCurrentValue(); if (Object.ReferenceEquals(_renderedGeometry, currentValue)) { _renderedGeometry = currentValue.Clone(); } else { _renderedGeometry = currentValue; } Transform renderedTransform = _renderedGeometry.Transform; BoxedMatrix boxedStretchMatrix = StretchMatrixField.GetValue(this); Matrix stretchMatrix = (boxedStretchMatrix == null) ? Matrix.Identity : boxedStretchMatrix.Value; if (renderedTransform == null || renderedTransform.IsIdentity) { _renderedGeometry.Transform = new MatrixTransform(stretchMatrix); } else { _renderedGeometry.Transform = new MatrixTransform(renderedTransform.Value * stretchMatrix); } } } } #endregion Internal Methods #region Private Fields private Pen _pen = null; private Geometry _renderedGeometry = Geometry.Empty; private static UncommonFieldStretchMatrixField = new UncommonField (null); #endregion Private Fields } internal class BoxedMatrix { public BoxedMatrix(Matrix value) { Value = value; } public Matrix Value; } } // 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
- NameValueConfigurationElement.cs
- ObjectTag.cs
- LayoutTable.cs
- ConfigurationLocationCollection.cs
- MatrixCamera.cs
- XmlSigningNodeWriter.cs
- DesignerSerializerAttribute.cs
- CodeVariableDeclarationStatement.cs
- DetailsViewCommandEventArgs.cs
- XmlAutoDetectWriter.cs
- CursorConverter.cs
- ReversePositionQuery.cs
- Point3DCollection.cs
- HtmlTableRow.cs
- HierarchicalDataSourceIDConverter.cs
- X500Name.cs
- SQLBinary.cs
- BufferedWebEventProvider.cs
- SafeFileMapViewHandle.cs
- IList.cs
- DataViewSetting.cs
- FontResourceCache.cs
- DBPropSet.cs
- ImageMapEventArgs.cs
- MediaTimeline.cs
- BindingExpressionUncommonField.cs
- GridViewActionList.cs
- ErrorFormatterPage.cs
- HebrewNumber.cs
- FileSecurity.cs
- Dynamic.cs
- Part.cs
- ControlCommandSet.cs
- StructuredTypeInfo.cs
- InlineUIContainer.cs
- DescendentsWalkerBase.cs
- FileRecordSequence.cs
- XmlSchemaComplexContent.cs
- UpdatePanel.cs
- SignedPkcs7.cs
- TextBoxLine.cs
- TrustSection.cs
- BaseParser.cs
- InputProviderSite.cs
- ToolStripInSituService.cs
- Helper.cs
- OLEDB_Util.cs
- IisNotInstalledException.cs
- ToolStripOverflow.cs
- RichTextBoxContextMenu.cs
- TextTreePropertyUndoUnit.cs
- Rfc2898DeriveBytes.cs
- MultipleViewPatternIdentifiers.cs
- Update.cs
- ValidatedMobileControlConverter.cs
- HwndProxyElementProvider.cs
- ProcessDesigner.cs
- SAPICategories.cs
- EpmContentSerializerBase.cs
- PersonalizationProvider.cs
- Aggregates.cs
- BitmapEditor.cs
- TransformValueSerializer.cs
- WorkflowServiceHostFactory.cs
- WindowsAuthenticationEventArgs.cs
- DefaultValueConverter.cs
- ContextMenu.cs
- DataGridViewTextBoxCell.cs
- RuleSetReference.cs
- X509CertificateCollection.cs
- ListViewTableCell.cs
- HtmlInputSubmit.cs
- PropertyGridView.cs
- ListBindingHelper.cs
- rsa.cs
- DesignBindingConverter.cs
- CssStyleCollection.cs
- XPathPatternBuilder.cs
- HiddenFieldDesigner.cs
- AutomationElement.cs
- EdmPropertyAttribute.cs
- AuthenticatingEventArgs.cs
- WsrmMessageInfo.cs
- SessionState.cs
- MouseEventArgs.cs
- IODescriptionAttribute.cs
- FamilyCollection.cs
- TextRangeProviderWrapper.cs
- DecodeHelper.cs
- IDispatchConstantAttribute.cs
- UnaryNode.cs
- DropSource.cs
- FileVersion.cs
- CompoundFileIOPermission.cs
- XmlTextAttribute.cs
- TextWriterTraceListener.cs
- CatalogPartCollection.cs
- SecurityTokenTypes.cs
- NamedPipeTransportSecurityElement.cs
- SemanticResultKey.cs