InkPresenter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / InkPresenter.cs / 1305600 / InkPresenter.cs

                            //---------------------------------------------------------------------------- 
//
// File: InkPresenter.cs
//
// Description: 
//      A rendering element which binds to the strokes data
// 
// Features: 
//
// History: 
//  12/02/2004 waynezen:       Created
//
// Copyright (C) 2001 by Microsoft Corporation.  All rights reserved.
// 
//---------------------------------------------------------------------------
 
using System; 
using System.Diagnostics;
using System.Collections.Generic; 
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls; 
using System.Windows.Ink;
using System.Windows.Threading; 
using System.Windows.Input; 
using MS.Internal.Ink;
using System.Windows.Automation.Peers; 

namespace System.Windows.Controls
{
    ///  
    /// Renders the specified StrokeCollection data.
    ///  
    public class InkPresenter : Decorator 
    {
 
        //-------------------------------------------------------------------------------
        //
        // Constructors
        // 
        //-------------------------------------------------------------------------------
 
        #region Constructors 

        ///  
        /// The constructor of InkPresenter
        /// 
        public InkPresenter()
        { 
            // Create the internal Renderer object.
            _renderer = new Ink.Renderer(); 
 
            SetStrokesChangedHandlers(this.Strokes, null);
 
            _contrastCallback = new InkPresenterHighContrastCallback(this);

            // Register rti high contrast callback. Then check whether we are under the high contrast already.
            HighContrastHelper.RegisterHighContrastCallback(_contrastCallback); 
            if ( SystemParameters.HighContrast )
            { 
                _contrastCallback.TurnHighContrastOn(SystemColors.WindowTextColor); 
            }
 
            _constraintSize = Size.Empty;
        }

        #endregion Constructors 

        //-------------------------------------------------------------------------------- 
        // 
        // Public Methods
        // 
        //-------------------------------------------------------------------------------

        #region Public Methods
 
        /// 
        /// AttachVisual method 
        ///  
        /// The stroke visual which needs to be attached
        /// The DrawingAttributes of the stroke 
        public void AttachVisuals(Visual visual, DrawingAttributes drawingAttributes)
        {
            VerifyAccess();
 
            EnsureRootVisual();
            _renderer.AttachIncrementalRendering(visual, drawingAttributes); 
        } 

        ///  
        /// DetachVisual method
        /// 
        /// The stroke visual which needs to be detached
        public void DetachVisuals(Visual visual) 
        {
            VerifyAccess(); 
 
            EnsureRootVisual();
            _renderer.DetachIncrementalRendering(visual); 
        }

        #endregion Public Methods
 
        //--------------------------------------------------------------------------------
        // 
        // Public Properties 
        //
        //-------------------------------------------------------------------------------- 

        #region Public Properties

        ///  
        /// The DependencyProperty for the Strokes property.
        ///  
        public static readonly DependencyProperty StrokesProperty = 
                DependencyProperty.Register(
                        "Strokes", 
                        typeof(StrokeCollection),
                        typeof(InkPresenter),
                        new FrameworkPropertyMetadata(
                                new StrokeCollectionDefaultValueFactory(), 
                                new PropertyChangedCallback(OnStrokesChanged)),
                        (ValidateValueCallback)delegate(object value) 
                            { return value != null; }); 

        ///  
        /// Gets/Sets the Strokes property.
        /// 
        public StrokeCollection Strokes
        { 
            get { return (StrokeCollection)GetValue(StrokesProperty); }
            set { SetValue(StrokesProperty, value); } 
        } 

        private static void OnStrokesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            InkPresenter inkPresenter = (InkPresenter)d;

            StrokeCollection oldValue = (StrokeCollection)e.OldValue; 
            StrokeCollection newValue = (StrokeCollection)e.NewValue;
 
            inkPresenter.SetStrokesChangedHandlers(newValue, oldValue); 
            inkPresenter.OnStrokeChanged(inkPresenter, EventArgs.Empty);
        } 


        #endregion Public Properties
 
        //-------------------------------------------------------------------------------
        // 
        // Protected Methods 
        //
        //-------------------------------------------------------------------------------- 

        #region Protected Methods

        ///  
        /// Override of 
        ///  
        /// Constraint size. 
        /// Computed desired size.
        protected override Size MeasureOverride(Size constraint) 
        {
            // No need to call VerifyAccess since we call the method on the base here.

            StrokeCollection strokes = Strokes; 

            // Measure the child first 
            Size newSize = base.MeasureOverride(constraint); 

            // If there are strokes in IP, we need to combine the size to final size. 
            if ( strokes != null && strokes.Count != 0 )
            {
                // Get the bounds of the stroks
                Rect boundingRect = StrokesBounds; 

                // If we have an empty bounding box or the Right/Bottom value is negative, 
                // an empty size will be returned. 
                if ( !boundingRect.IsEmpty && boundingRect.Right > 0.0 && boundingRect.Bottom > 0.0 )
                { 
                    // The new size needs to contain the right boundary and bottom boundary.
                    Size sizeStrokes = new Size(boundingRect.Right, boundingRect.Bottom);

                    newSize.Width = Math.Max(newSize.Width, sizeStrokes.Width); 
                    newSize.Height = Math.Max(newSize.Height, sizeStrokes.Height);
                } 
            } 

            if ( Child != null ) 
            {
                _constraintSize = constraint;
            }
            else 
            {
                _constraintSize = Size.Empty; 
            } 

            return newSize; 
        }

        /// 
        /// Override of . 
        /// 
        /// Size that element should use to arrange itself and its children. 
        /// The InkPresenter's desired size. 
        protected override Size ArrangeOverride(Size arrangeSize)
        { 
            VerifyAccess();

            EnsureRootVisual();
 
            // NTRAID-WINDOWSOS#1091908-WAYNEZEN,
            // When we arrange the child, we shouldn't count in the strokes' bounds. 
            // We only use the constraint size for the child. 
            Size availableSize = arrangeSize;
            if ( !_constraintSize.IsEmpty ) 
            {
                availableSize = new Size(Math.Min(arrangeSize.Width, _constraintSize.Width),
                                                Math.Min(arrangeSize.Height, _constraintSize.Height));
            } 

            // We arrange our child as what Decorator does 
            // exceopt we are using the available size computed from our cached measure size. 
            UIElement child = Child;
            if ( child != null ) 
            {
                child.Arrange(new Rect(availableSize));
            }
 
            return arrangeSize;
        } 
 
        /// 
        /// The overridden GetLayoutClip method 
        /// 
        /// Geometry to use as additional clip if ClipToBounds=true
        protected override Geometry GetLayoutClip(Size layoutSlotSize)
        { 
            // NTRAID:WINDOWSOS#1516798-2006/02/17-WAYNEZEN
            // By default an FE will clip its content if the ink size exceeds the layout size (the final arrange size). 
            // Since we are auto growing, the ink size is same as the desired size. So it ends up the strokes will be clipped 
            // regardless ClipToBounds is set or not.
            // We override the GetLayoutClip method so that we can bypass the default layout clip if ClipToBounds is set to false. 
            // So we allow the ink to be drown anywhere when no clip is set.
            if ( ClipToBounds )
            {
                return base.GetLayoutClip(layoutSlotSize); 
            }
            else 
                return null; 
        }
 
        /// 
        /// Returns the child at the specified index.
        /// 
        protected override Visual GetVisualChild(int index) 
        {
            int count = VisualChildrenCount; 
 
            if(count == 2)
            { 
                switch (index)
                {
                    case 0:
                        return  base.Child; 

                    case 1: 
                        return _renderer.RootVisual; 

                    default: 
                        throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
                }
            }
            else if (index == 0 && count == 1) 
            {
                if ( _hasAddedRoot ) 
                { 
                    return _renderer.RootVisual;
                } 
                else if(base.Child != null)
                {
                    return base.Child;
                } 
            }
            throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); 
        } 

 
        /// 
        ///  Derived classes override this property to enable the Visual code to enumerate
        ///  the Visual children. Derived classes need to return the number of children
        ///  from this method. 
        ///
        ///    By default a Visual does not have any children. 
        /// 
        ///  Remark: During this virtual method the Visual tree must not be modified.
        ///  
        protected override int VisualChildrenCount
        {
            get
            { 
                // we can have 4 states:-
                // 1. no children 
                // 2. only base.Child 
                // 3. only _renderer.RootVisual as the child
                // 4. both base.Child and  _renderer.RootVisual 

                if(base.Child != null)
                {
                    if ( _hasAddedRoot ) 
                    {
                       return 2; 
                    } 
                    else
                    { 
                        return 1;
                    }
                }
                else if ( _hasAddedRoot ) 
                {
                    return 1; 
                } 

                return 0; 
            }
        }

        ///  
        /// UIAutomation support
        ///  
        protected override AutomationPeer OnCreateAutomationPeer() 
        {
            return new InkPresenterAutomationPeer(this); 
        }


        #endregion Protected Methods 

        #region Internal Methods 
 
        /// 
        /// Internal helper used to indicate if a visual was previously attached 
        /// via a call to AttachIncrementalRendering
        /// 
        internal bool ContainsAttachedVisual(Visual visual)
        { 
            VerifyAccess();
            return _renderer.ContainsAttachedIncrementalRenderingVisual(visual); 
        } 

 
        /// 
        /// Internal helper used to determine if a visual is in the right spot in the visual tree
        /// 
        internal bool AttachedVisualIsPositionedCorrectly(Visual visual, DrawingAttributes drawingAttributes) 
        {
            VerifyAccess(); 
            return _renderer.AttachedVisualIsPositionedCorrectly(visual, drawingAttributes); 
        }
 
        #endregion Internal Methods
        //-----------------------------------------------------
        //
        //  Private Classes 
        //
        //----------------------------------------------------- 
 
        #region Private Classes
 
        /// 
        /// A helper class for the high contrast support
        /// 
        private class InkPresenterHighContrastCallback : HighContrastCallback 
        {
            //----------------------------------------------------- 
            // 
            //  Cnostructors
            // 
            //------------------------------------------------------

            #region Constructors
 
            internal InkPresenterHighContrastCallback(InkPresenter inkPresenter)
            { 
                _thisInkPresenter = inkPresenter; 
            }
 
            private InkPresenterHighContrastCallback() { }

            #endregion Constructors
 
            //-----------------------------------------------------
            // 
            //  Internal Methods 
            //
            //------------------------------------------------------ 

            #region Internal Methods

            ///  
            /// TurnHighContrastOn
            ///  
            ///  
            internal override void TurnHighContrastOn(Color highContrastColor)
            { 
                _thisInkPresenter._renderer.TurnHighContrastOn(highContrastColor);
                _thisInkPresenter.OnStrokeChanged();
            }
 
            /// 
            /// TurnHighContrastOff 
            ///  
            internal override void TurnHighContrastOff()
            { 
                _thisInkPresenter._renderer.TurnHighContrastOff();
                _thisInkPresenter.OnStrokeChanged();
            }
 
            #endregion Internal Methods
 
            //------------------------------------------------------ 
            //
            //  Internal Properties 
            //
            //-----------------------------------------------------

            #region Internal Properties 

            ///  
            /// Returns the dispatcher if the object is associated to a UIContext. 
            /// 
            internal override Dispatcher Dispatcher 
            {
                get
                {
                    return _thisInkPresenter.Dispatcher; 
                }
            } 
 
            #endregion Internal Properties
 
            //------------------------------------------------------
            //
            //  Private Fields
            // 
            //-----------------------------------------------------
 
            #region Private Fields 

            private InkPresenter _thisInkPresenter; 

            #endregion Private Fields
        }
 
        #endregion Private Classes
 
        //------------------------------------------------------------------------------- 
        //
        // Private Methods 
        //
        //-------------------------------------------------------------------------------

        #region Private Methods 

        private void SetStrokesChangedHandlers(StrokeCollection newStrokes, StrokeCollection oldStrokes) 
        { 
            Debug.Assert(newStrokes != null, "Cannot set a null to InkPresenter");
 
            // Remove the event handlers from the old stroke collection
            if ( null != oldStrokes )
            {
                // Stop listening on events from the stroke collection. 
                oldStrokes.StrokesChanged -= new StrokeCollectionChangedEventHandler(OnStrokesChanged);
            } 
 
            // Start listening on events from the stroke collection.
            newStrokes.StrokesChanged += new StrokeCollectionChangedEventHandler(OnStrokesChanged); 

            // Replace the renderer stroke collection.
            _renderer.Strokes = newStrokes;
 
            SetStrokeChangedHandlers(newStrokes, oldStrokes);
        } 
 
        /// 
        /// StrokeCollectionChanged event handler 
        /// 
        private void OnStrokesChanged(object sender, StrokeCollectionChangedEventArgs eventArgs)
        {
            System.Diagnostics.Debug.Assert(sender == this.Strokes); 

            SetStrokeChangedHandlers(eventArgs.Added, eventArgs.Removed); 
            OnStrokeChanged(this, EventArgs.Empty); 
        }
 
        private void SetStrokeChangedHandlers(StrokeCollection addedStrokes, StrokeCollection removedStrokes)
        {
            Debug.Assert(addedStrokes != null, "The added StrokeCollection cannot be null.");
            int count, i; 

            if ( removedStrokes != null ) 
            { 
                // Deal with removed strokes first
                count = removedStrokes.Count; 
                for ( i = 0; i < count; i++ )
                {
                    StopListeningOnStrokeEvents(removedStrokes[i]);
                } 
            }
 
            // Add new strokes 
            count = addedStrokes.Count;
            for ( i = 0; i < count; i++ ) 
            {
                StartListeningOnStrokeEvents(addedStrokes[i]);
            }
        } 

        private void OnStrokeChanged(object sender, EventArgs e) 
        { 
            OnStrokeChanged();
        } 

        /// 
        /// The method is called from Stroke setter, OnStrokesChanged, DrawingAttributesChanged and OnPacketsChanged
        ///  
        private void OnStrokeChanged()
        { 
            // Recalculate the bound of the StrokeCollection 
            _cachedBounds = null;
            // Invalidate the current measure when any change happens on the stroke or strokes. 
            InvalidateMeasure();
        }

        ///  
        /// Attaches event handlers to stroke events
        ///  
        private void StartListeningOnStrokeEvents(Stroke stroke) 
        {
            System.Diagnostics.Debug.Assert(stroke != null); 
            stroke.Invalidated += new EventHandler(OnStrokeChanged);
        }

        ///  
        /// Detaches event handlers from stroke
        ///  
        private void StopListeningOnStrokeEvents(Stroke stroke) 
        {
            System.Diagnostics.Debug.Assert(stroke != null); 
            stroke.Invalidated -= new EventHandler(OnStrokeChanged);
        }

        ///  
        /// Ensure the renderer root to be connected. The method is called from
        ///     AttachVisuals 
        ///     DetachVisuals 
        ///     ArrangeOverride
        ///  
        private void EnsureRootVisual()
        {
            if ( !_hasAddedRoot )
            { 
                AddVisualChild(_renderer.RootVisual);
                _hasAddedRoot = true; 
            } 
        }
 
        #endregion Private Methods

        //--------------------------------------------------------------------------------
        // 
        // Private Properties
        // 
        //------------------------------------------------------------------------------- 

        #region Private Properties 

        private Rect StrokesBounds
        {
            get 
            {
                if ( _cachedBounds == null ) 
                { 
                    _cachedBounds = Strokes.GetBounds();
                } 

                return _cachedBounds.Value;
            }
        } 

        #endregion Private Properties 
 
        //--------------------------------------------------------------------------------
        // 
        // Private Fields
        //
        //--------------------------------------------------------------------------------
 
        #region Private Fields
        private Ink.Renderer    _renderer; 
        private Nullable  _cachedBounds = null; 
        private bool            _hasAddedRoot;
        // 
        // HighContrast support
        //
        private InkPresenterHighContrastCallback    _contrastCallback;
 
        private Size                                _constraintSize;
 
        #endregion Private Fields 

    } 
}



// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK