BulletDecorator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Controls / Primitives / BulletDecorator.cs / 1 / BulletDecorator.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

using MS.Internal; 
using MS.Utility; 
using MS.Internal.Documents;
using System; 
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; 
using System.Diagnostics;
using System.Windows.Threading; 
using System.Windows.Documents; 
using System.Windows.Media;
 
namespace System.Windows.Controls.Primitives
{
    /// 
    ///     BulletDecorator is used for decorating a generic content of type UIElement. 
    /// Usually, the content is a text and the bullet is a glyph representing
    /// something similar to a checkbox or a radiobutton. 
    /// Bullet property is used to decorate the content by aligning itself with the first line of the content text. 
    /// 
    public class BulletDecorator : Decorator 
    {
        //-------------------------------------------------------------------
        //
        //  Constructors 
        //
        //------------------------------------------------------------------- 
 
        #region Constructors
 
        /// 
        ///     Default BulletDecorator constructor
        /// 
        ///  
        ///     Automatic determination of current Dispatcher.
        /// Use alternative constructor that accepts a Dispatcher for best performance. 
        ///  
        public BulletDecorator() : base()
        { 
        }

        #endregion
 
        //--------------------------------------------------------------------
        // 
        //  Constructors 
        //
        //------------------------------------------------------------------- 

        #region Properties

        ///  
        /// DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty BackgroundProperty = 
                Panel.BackgroundProperty.AddOwner(typeof(BulletDecorator),
                        new FrameworkPropertyMetadata( 
                                (Brush)null,
                                FrameworkPropertyMetadataOptions.AffectsRender));

        ///  
        /// The Background property defines the brush used to fill the area within the BulletDecorator.
        ///  
        public Brush Background 
        {
            get { return (Brush)GetValue(BackgroundProperty); } 
            set { SetValue(BackgroundProperty, value); }
        }

        ///  
        /// Bullet property is the first visual element in BulletDecorator visual tree.
        /// It should be aligned to BulletDecorator.Child which is the second visual child. 
        ///  
        /// 
        public UIElement Bullet 
        {
            get
            {
                return _bullet; 
            }
            set 
            { 
                if (_bullet != value)
                { 
                    if (_bullet != null)
                    {
                        // notify the visual layer that the old bullet has been removed.
                        RemoveVisualChild(_bullet); 

                        //need to remove old element from logical tree 
                        RemoveLogicalChild(_bullet); 
                    }
 
                    _bullet = value;

                    AddLogicalChild(value);
                    // notify the visual layer about the new child. 
                    AddVisualChild(value);
 
                    // If we decorator content exists we need to move it at the end of the visual tree 
                    UIElement child = Child;
                    if (child != null) 
                    {
                        RemoveVisualChild(child);
                        AddVisualChild(child);
                    } 

                    InvalidateMeasure(); 
                } 
            }
        } 

        #endregion Properties

        //-------------------------------------------------------------------- 
        //
        //  Protected Methods 
        // 
        //--------------------------------------------------------------------
 
        #region Protected Methods

        /// 
        /// Returns enumerator to logical children. 
        /// 
        protected internal override IEnumerator LogicalChildren 
        { 
            get
            { 
                if (_bullet == null)
                {
                    return base.LogicalChildren;
                } 

                if (Child == null) 
                { 
                    return new SingleChildEnumerator(_bullet);
                } 

                return new DoubleChildEnumerator(_bullet, Child);
            }
        } 

        private class DoubleChildEnumerator : IEnumerator 
        { 
            internal DoubleChildEnumerator(object child1, object child2)
            { 
                Debug.Assert(child1 != null, "First child should be non-null.");
                Debug.Assert(child2 != null, "Second child should be non-null.");

                _child1 = child1; 
                _child2 = child2;
            } 
 
            object IEnumerator.Current
            { 
                get
                {
                    switch (_index)
                    { 
                        case 0:
                            return _child1; 
                        case 1: 
                            return _child2;
                        default: 
                            return null;
                    }
                }
            } 

            bool IEnumerator.MoveNext() 
            { 
                _index++;
                return _index < 2; 
            }

            void IEnumerator.Reset()
            { 
                _index = -1;
            } 
 
            private int _index = -1;
            private object _child1; 
            private object _child2;
        }

        ///  
        /// Override from UIElement
        ///  
        protected override void OnRender(DrawingContext dc) 
        {
            // Draw background in rectangle inside border. 
            Brush background = this.Background;
            if (background != null)
            {
                dc.DrawRectangle(background, 
                                 null,
                                 new Rect(0, 0, RenderSize.Width, RenderSize.Height)); 
            } 
        }
 
        /// 
        /// Returns the Visual children count.
        /// 
        protected override int VisualChildrenCount 
        {
            get { return (Child == null ? 0 : 1) + (_bullet == null ? 0 : 1); } 
        } 

        ///  
        /// Returns the child at the specified index.
        /// 
        protected override Visual GetVisualChild(int index)
        { 
            if (index < 0 || index > VisualChildrenCount-1)
            { 
                throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); 
            }
 
            if (index == 0 && _bullet != null)
            {
                return _bullet;
            } 

            return Child; 
        } 
        /// 
        /// Updates DesiredSize of the BulletDecorator. Called by parent UIElement. 
        /// This is the first pass of layout.
        /// 
        /// Constraint size is an "upper limit" that BulletDecorator should not exceed.
        /// BulletDecorator' desired size. 
        protected override Size MeasureOverride(Size constraint)
        { 
                Size bulletSize = new Size(); 
                Size contentSize = new Size();
                UIElement bullet = Bullet; 
                UIElement content = Child;

                // If we have bullet we should measure it first
                if (bullet != null) 
                {
                    bullet.Measure(constraint); 
                    bulletSize = bullet.DesiredSize; 
                }
 
                // If we have second child (content) we should measure it
                if (content != null)
                {
                    Size contentConstraint = constraint; 
                    contentConstraint.Width = Math.Max(0.0, contentConstraint.Width - bulletSize.Width);
 
                    content.Measure(contentConstraint); 
                    contentSize = content.DesiredSize;
                } 

                Size desiredSize = new Size(bulletSize.Width + contentSize.Width, Math.Max(bulletSize.Height, contentSize.Height));
                return desiredSize;
 
        }
 
        ///  
        /// BulletDecorator arranges its children - Bullet and Child.
        /// Bullet is aligned vertically with the center of the content's first line 
        /// 
        /// Size that BulletDecorator will assume to position children.
        protected override Size ArrangeOverride(Size arrangeSize)
        { 
                UIElement bullet = Bullet;
                UIElement content = Child; 
                double contentOffsetX = 0; 

                double bulletOffsetY = 0; 

                Size bulletSize = new Size();

                // Arrange the bullet if exist 
                if (bullet != null)
                { 
                    bullet.Arrange(new Rect(bullet.DesiredSize)); 
                    bulletSize = bullet.RenderSize;
 
                    contentOffsetX = bulletSize.Width;
                }

                // Arrange the content if exist 
                if (content != null)
                { 
                    // Helper arranges child and may substitute a child's explicit properties for its DesiredSize. 
                    // The actual size the child takes up is stored in its RenderSize.
                    Size contentSize = arrangeSize; 
                    if (bullet != null)
                    {
                        contentSize.Width = Math.Max(content.DesiredSize.Width, arrangeSize.Width - bullet.DesiredSize.Width);
                        contentSize.Height = Math.Max(content.DesiredSize.Height, arrangeSize.Height); 
                    }
                    content.Arrange(new Rect(contentOffsetX, 0, contentSize.Width, contentSize.Height)); 
 
                    double centerY = GetFirstLineHeight(content) * 0.5d;
                    bulletOffsetY += Math.Max(0d, centerY - bulletSize.Height * 0.5d); 
                }

                // Re-Position the bullet if exist
                if (bullet != null && !DoubleUtil.IsZero(bulletOffsetY)) 
                {
                    bullet.Arrange(new Rect(0, bulletOffsetY, bullet.DesiredSize.Width, bullet.DesiredSize.Height)); 
                } 

                return arrangeSize; 
        }

        #endregion Protected Methods
 
        //-------------------------------------------------------------------
        // 
        //  Private Methods 
        //
        //-------------------------------------------------------------------- 

        #region Private Methods

        // This method calculates the height of the first line if the element is TextBlock or FlowDocumentScrollViewer 
        // Otherwise returns the element height
        private double GetFirstLineHeight(UIElement element) 
        { 
            // We need to find TextBlock/FlowDocumentScrollViewer if it is nested inside ContentPresenter
            // Common scenario when used in styles is that BulletDecorator content is a ContentPresenter 
            UIElement text = FindText(element);
            ReadOnlyCollection lr = null;
            if (text != null)
            { 
                TextBlock textElement = ((TextBlock)text);
                if (textElement.IsLayoutDataValid) 
                    lr = textElement.GetLineResults(); 
            }
            else 
            {
                text = FindFlowDocumentScrollViewer(element);
                if (text != null)
                { 
                    TextDocumentView tdv = ((IServiceProvider)text).GetService(typeof(ITextView)) as TextDocumentView;
                    if (tdv != null && tdv.IsValid) 
                    { 
                        ReadOnlyCollection cr = tdv.Columns;
                        if (cr != null && cr.Count > 0) 
                        {
                            ColumnResult columnResult = cr[0];
                            ReadOnlyCollection pr = columnResult.Paragraphs;
                            if (pr != null && pr.Count > 0) 
                            {
                                ContainerParagraphResult cpr = pr[0] as ContainerParagraphResult; 
                                if (cpr != null) 
                                {
                                    TextParagraphResult textParagraphResult = cpr.Paragraphs[0] as TextParagraphResult; 
                                    if (textParagraphResult != null)
                                    {
                                        lr = textParagraphResult.Lines;
                                    } 
                                }
                            } 
                        } 
                    }
                } 
            }

            if (lr != null && lr.Count > 0)
            { 
                Point ancestorOffset = new Point();
                text.TransformToAncestor(element).TryTransform(ancestorOffset, out ancestorOffset); 
                return lr[0].LayoutBox.Height + ancestorOffset.Y * 2d; 
            }
 
            return element.RenderSize.Height;
        }

        private TextBlock FindText(Visual root) 
        {
            TextBlock text = root as TextBlock; 
            if (text != null) 
                return text;
 
            ContentPresenter cp = root as ContentPresenter;
            if (cp != null)
            {
                if(VisualTreeHelper.GetChildrenCount(cp) == 1) 
                    return VisualTreeHelper.GetChild(cp, 0) as TextBlock;
            } 
            return null; 
        }
 
        private FlowDocumentScrollViewer FindFlowDocumentScrollViewer(Visual root)
        {
            FlowDocumentScrollViewer text = root as FlowDocumentScrollViewer;
            if (text != null) 
                return text;
 
            ContentPresenter cp = root as ContentPresenter; 
            if (cp != null)
            { 
                if(VisualTreeHelper.GetChildrenCount(cp) == 1)
                    return VisualTreeHelper.GetChild(cp, 0) as FlowDocumentScrollViewer;
            }
            return null; 
        }
 
        #endregion 

        //------------------------------------------------------------------- 
        //
        //  Private Memebers
        //
        //------------------------------------------------------------------- 

        #region Private Members 
        UIElement _bullet = null; 
        #endregion Private Members
 
    }
}


// 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