AccessText.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / AccessText.cs / 1 / AccessText.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 
using System.Collections;
using System.ComponentModel; 
using System.Windows.Data; 
using System.Windows.Documents;
using System.Windows.Input; 
using System.Windows.Media;
using System.Windows.Markup;
using System.Diagnostics;
using System.Xml; 

using MS.Internal; 
 
namespace System.Windows.Controls
{ 
    /// 
    /// AccessText Element - Register an accesskey specified after the underscore character in the text.
    /// 
    [ContentProperty("Text")] 
    public class AccessText : FrameworkElement, IAddChild
    { 
        //------------------------------------------------------------------- 
        //
        //  IContentHost Members 
        //
        //-------------------------------------------------------------------

        #region IAddChild members 

        /// 
        /// Called to Add the object as a Child. 
        ///
        /// 
        /// Object to add as a child
        ///
        void IAddChild.AddChild(Object value)
        { 
            ((IAddChild)TextBlock).AddChild(value);
        } 
 
        ///
        /// Called when text appears under the tag in markup. 
        ///
        ///
        /// Text to Add to the Object
        /// 
        void IAddChild.AddText(string text)
        { 
            ((IAddChild)TextBlock).AddText(text); 
        }
 
        #endregion IAddChild members

        //--------------------------------------------------------------------
        // 
        //  LogicalTree
        // 
        //------------------------------------------------------------------- 

        #region LogicalTree 

        /// 
        /// Returns enumerator to logical children.
        ///  
        protected internal override IEnumerator LogicalChildren
        { 
            get 
            {
                return new RangeContentEnumerator(TextContainer.Start, TextContainer.End); 
            }
        }

        #endregion LogicalTree 

        //-------------------------------------------------------------------- 
        // 
        //  Constructors
        // 
        //--------------------------------------------------------------------

        #region Constructors
 
        /// 
        /// AccessText constructor. 
        ///  
        public AccessText() : base()
        { 
        }

        #endregion Constructors
 
        //-------------------------------------------------------------------
        // 
        //  Public Properties 
        //
        //-------------------------------------------------------------------- 

        #region Public Properties

        ///  
        ///     Read only access to the key after the first underline character
        ///  
        public char AccessKey 
        {
            get 
            {
                //
                return (_accessKey != null && _accessKey.Text.Length > 0) ? _accessKey.Text[0] : (char)0;
            } 
        }
 
        #endregion Public Properties 

        //------------------------------------------------------------------- 
        //
        //  Public Dynamic Properties
        //
        //------------------------------------------------------------------- 

        #region Public Dynamic Properties 
 
        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty TextProperty =
                DependencyProperty.Register(
                        "Text", 
                        typeof(string),
                        typeof(AccessText), 
                        new FrameworkPropertyMetadata( 
                                string.Empty,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, 
                                new PropertyChangedCallback(OnTextChanged)));

        /// 
        /// The Text property defines the text to be displayed. 
        /// 
        [DefaultValue("")] 
        public string Text 
        {
            get { return (string) GetValue(TextProperty); } 
            set { SetValue(TextProperty, value); }
        }

 
        /// 
        /// DependencyProperty for  property. 
        ///  
        public static readonly DependencyProperty FontFamilyProperty =
                TextElement.FontFamilyProperty.AddOwner(typeof(AccessText)); 

        /// 
        /// The FontFamily property specifies the name of font family.
        ///  
        [Localizability(
            LocalizationCategory.Font, 
            Modifiability = Modifiability.Unmodifiable 
        )]
        public FontFamily FontFamily 
        {
            get { return (FontFamily) GetValue(FontFamilyProperty); }
            set { SetValue(FontFamilyProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty FontStyleProperty = 
                TextElement.FontStyleProperty.AddOwner(typeof(AccessText));

        /// 
        /// The FontStyle property requests normal, italic, and oblique faces within a font family. 
        /// 
        public FontStyle FontStyle 
        { 
            get { return (FontStyle) GetValue(FontStyleProperty); }
            set { SetValue(FontStyleProperty, value); } 
        }

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty FontWeightProperty = 
                TextElement.FontWeightProperty.AddOwner(typeof(AccessText)); 

        ///  
        /// The FontWeight property specifies the weight of the font.
        /// 
        public FontWeight FontWeight
        { 
            get { return (FontWeight) GetValue(FontWeightProperty); }
            set { SetValue(FontWeightProperty, value); } 
        } 

        ///  
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty FontStretchProperty =
                TextElement.FontStretchProperty.AddOwner(typeof(AccessText)); 

        ///  
        /// The FontStretch property selects a normal, condensed, or extended face from a font family. 
        /// 
        public FontStretch FontStretch 
        {
            get { return (FontStretch) GetValue(FontStretchProperty); }
            set { SetValue(FontStretchProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty FontSizeProperty = 
                TextElement.FontSizeProperty.AddOwner(typeof(AccessText));

        /// 
        /// The FontSize property specifies the size of the font. 
        /// 
        [TypeConverter(typeof(FontSizeConverter))] 
        [Localizability(LocalizationCategory.None)] 
        public double FontSize
        { 
            get { return (double) GetValue(FontSizeProperty); }
            set { SetValue(FontSizeProperty, value); }
        }
 
        /// 
        /// DependencyProperty for  property. 
        ///  
        public static readonly DependencyProperty ForegroundProperty =
                TextElement.ForegroundProperty.AddOwner(typeof(AccessText)); 

        /// 
        /// The Foreground property specifies the foreground brush of an element's text content.
        ///  
        public Brush Foreground
        { 
            get { return (Brush) GetValue(ForegroundProperty); } 
            set { SetValue(ForegroundProperty, value); }
        } 

        /// 
        /// DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty BackgroundProperty =
                TextElement.BackgroundProperty.AddOwner( 
                        typeof(AccessText), 
                        new FrameworkPropertyMetadata(
                                null, 
                                FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged)));

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

        ///  
        /// DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty TextDecorationsProperty = 
                Inline.TextDecorationsProperty.AddOwner(
                        typeof(AccessText), 
                        new FrameworkPropertyMetadata(
                                new FreezableDefaultValueFactory(TextDecorationCollection.Empty),
                                FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged))); 

        ///  
        /// The TextDecorations property specifies decorations that are added to the text of an element. 
        /// 
        public TextDecorationCollection TextDecorations 
        {
            get { return (TextDecorationCollection) GetValue(TextDecorationsProperty); }
            set { SetValue(TextDecorationsProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty TextEffectsProperty = 
                TextElement.TextEffectsProperty.AddOwner(
                        typeof(AccessText),
                        new FrameworkPropertyMetadata(
                                new FreezableDefaultValueFactory(TextEffectCollection.Empty), 
                                FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged))); 
 
        /// 
        /// The TextEffects property specifies effects that are added to the text of an element. 
        /// 
        public TextEffectCollection TextEffects
        {
            get { return (TextEffectCollection) GetValue(TextEffectsProperty); } 
            set { SetValue(TextEffectsProperty, value); }
        } 
 
        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty LineHeightProperty =
                Block.LineHeightProperty.AddOwner(typeof(AccessText));
 
        /// 
        /// The LineHeight property specifies the height of each generated line box. 
        ///  
        [TypeConverter(typeof(LengthConverter))]
        public double LineHeight 
        {
            get { return (double) GetValue(LineHeightProperty); }
            set { SetValue(LineHeightProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty LineStackingStrategyProperty = 
                Block.LineStackingStrategyProperty.AddOwner(typeof(AccessText));

        /// 
        /// The LineStackingStrategy property specifies how lines are placed 
        /// 
        public LineStackingStrategy LineStackingStrategy 
        { 
            get { return (LineStackingStrategy)GetValue(LineStackingStrategyProperty); }
            set { SetValue(LineStackingStrategyProperty, value); } 
        }

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty TextAlignmentProperty = 
                Block.TextAlignmentProperty.AddOwner(typeof(AccessText)); 

        ///  
        /// The TextAlignment property specifies horizontal alignment of the content.
        /// 
        public TextAlignment TextAlignment
        { 
            get { return (TextAlignment) GetValue(TextAlignmentProperty); }
            set { SetValue(TextAlignmentProperty, value); } 
        } 

        ///  
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty TextTrimmingProperty =
                TextBlock.TextTrimmingProperty.AddOwner( 
                        typeof(AccessText),
                        new FrameworkPropertyMetadata( 
                                TextTrimming.None, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged))); 

        /// 
        /// The TextTrimming property specifies the trimming behavior situation
        /// in case of clipping some textual content caused by overflowing the line's box. 
        /// 
        public TextTrimming TextTrimming 
        { 
            get { return (TextTrimming) GetValue(TextTrimmingProperty); }
            set { SetValue(TextTrimmingProperty, value); } 
        }

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty TextWrappingProperty = 
                TextBlock.TextWrappingProperty.AddOwner( 
                        typeof(AccessText),
                        new FrameworkPropertyMetadata( 
                                TextWrapping.NoWrap,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged)));
 
        /// 
        /// The TextWrapping property controls whether or not text wraps 
        /// when it reaches the flow edge of its containing block box. 
        /// 
        public TextWrapping TextWrapping 
        {
            get { return (TextWrapping) GetValue(TextWrappingProperty); }
            set { SetValue(TextWrappingProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty BaselineOffsetProperty = 
                TextBlock.BaselineOffsetProperty.AddOwner(typeof(AccessText), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnPropertyChanged)));

        /// 
        /// The BaselineOffset property provides an adjustment to baseline offset 
        /// 
        public double BaselineOffset 
        { 
            get { return (double) GetValue(BaselineOffsetProperty); }
            set { SetValue(BaselineOffsetProperty, value); } 
        }

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

        #region Protected Methods

        ///  
        /// Content measurement.
        ///  
        /// Constraint size. 
        /// Computed desired size.
        protected sealed override Size MeasureOverride(Size constraint) 
        {
            TextBlock.Measure(constraint);
            return TextBlock.DesiredSize;
        } 

        ///  
        /// Content arrangement. 
        /// 
        /// Size that element should use to arrange itself and its children. 
        protected sealed override Size ArrangeOverride(Size arrangeSize)
        {
            TextBlock.Arrange(new Rect(arrangeSize));
            return arrangeSize; 
        }
 
        #endregion Protected Methods 

        //------------------------------------------------------------------- 
        //
        //  Internal Methods
        //
        //-------------------------------------------------------------------- 

        #region Internal Methods 
 
        internal static bool HasCustomSerialization(object o)
        { 
            Run accessKey = o as Run;
            return accessKey != null && HasCustomSerializationStorage.GetValue(accessKey);
        }
 
        #endregion Internal methods
 
        //-------------------------------------------------------------------- 
        //
        //  Internal Properties 
        //
        //-------------------------------------------------------------------

        #region Internal Properties 

        internal TextBlock TextBlock 
        { 
            get
            { 
                if (_textBlock == null)
                    CreateTextBlock();
                return _textBlock;
            } 
        }
 
 
        internal static char AccessKeyMarker
        { 
            get { return _accessKeyMarker; }
        }

        #endregion Internal Properties 

        //-------------------------------------------------------------------- 
        // 
        //  Private Methods
        // 
        //-------------------------------------------------------------------

        #region Private Methods
 
        private TextContainer TextContainer
        { 
            get 
            {
                if (_textContainer == null) 
                    CreateTextBlock();
                return _textContainer;
            }
        } 

        private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
            ((AccessText)d).TextBlock.SetValue(e.Property, e.NewValue);
        } 

        /// 
        /// CreateTextBlock - Creates a text block, adds as visual child, databinds properties and sets up appropriate event listener.
        ///  
        private void CreateTextBlock()
        { 
            _textContainer = new TextContainer(this, false /* plainTextOnly */); 
            _textBlock = new TextBlock();
            AddVisualChild(_textBlock); 
            _textBlock.IsContentPresenterContainer = true;
            _textBlock.SetTextContainer(_textContainer);
            InitializeTextContainerListener();
        } 

        ///  
        /// Gets the Visual children count of the AccessText control. 
        /// 
        protected override int VisualChildrenCount 
        {
            get { return 1; }
        }
 
        /// 
        /// Gets the Visual child at the specified index. 
        ///  
        protected override Visual GetVisualChild(int index)
        { 
            if (index != 0)
            {
                throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
            } 
            return TextBlock;
        } 
 
        // Provides custom serialization for this element
        internal static void SerializeCustom(XmlWriter xmlWriter, object o) 
        {
            Run inlineScope = o as Run;
            if (inlineScope != null)
            { 
                xmlWriter.WriteString(AccessKeyMarker + inlineScope.Text);
            } 
        } 

        private static Style AccessKeyStyle 
        {
            get
            {
                if (_accessKeyStyle == null) 
                {
                    Style accessKeyStyle = new Style(typeof(Run)); 
                    Trigger trigger = new Trigger(); 
                    trigger.Property = KeyboardNavigation.ShowKeyboardCuesProperty;
                    trigger.Value = true; 
                    trigger.Setters.Add(new Setter(TextDecorationsProperty, System.Windows.TextDecorations.Underline));
                    accessKeyStyle.Triggers.Add(trigger);
                    accessKeyStyle.Seal();
                    _accessKeyStyle = accessKeyStyle; 
                }
                return _accessKeyStyle; 
            } 
        }
 
        /// 
        /// UpdateAccessKey - Scans forward in the tree looking for the access key marker, replacing it with access key element. We only support one find.
        /// 
        private void UpdateAccessKey() 
        {
            TextPointer navigator = new TextPointer(TextContainer.Start); 
 
            while (!_accessKeyLocated && navigator.CompareTo(TextContainer.End) < 0 )
            { 
                TextPointerContext symbolType = navigator.GetPointerContext(LogicalDirection.Forward);
                switch (symbolType)
                {
                    case TextPointerContext.Text: 
                        string text = navigator.GetTextInRun(LogicalDirection.Forward);
                        int index = FindAccessKeyMarker(text); 
                        if(index != -1 && index < text.Length - 1) 
                        {
                            TextPointer keyStart = navigator.GetPositionAtOffset(index + 1); 
                            TextPointer keyEnd = keyStart.GetNextInsertionPosition(LogicalDirection.Forward);
                            int accessKeyLength = keyStart.GetOffsetToPosition(keyEnd);

                            _accessKey = new Run(text.Substring(index + 1, accessKeyLength)); 
                            _accessKey.Style = AccessKeyStyle;
 
                            RegisterAccessKey(); 

                            HasCustomSerializationStorage.SetValue(_accessKey, true); 
                            _accessKeyLocated = true;

                            UninitializeTextContainerListener();
 
                            TextContainer.BeginChange();
                            try 
                            { 
                                TextPointer underlineStart = new TextPointer(navigator, index);
                                TextRangeEdit.DeleteInlineContent(underlineStart, keyEnd); 
                                _accessKey.RepositionWithContent(underlineStart);

                            }
                            finally 
                            {
                                TextContainer.EndChange(); 
                                InitializeTextContainerListener(); 
                            }
                        } 

                        break;
                }
                navigator.MoveToNextContextPosition(LogicalDirection.Forward); 
            }
 
            // Convert double _ to single _ 
            navigator = new TextPointer(TextContainer.Start);
            string accessKeyMarker = AccessKeyMarker.ToString(); 
            string doubleAccessKeyMarker = accessKeyMarker + accessKeyMarker;
            while (navigator.CompareTo(TextContainer.End) < 0)
            {
                TextPointerContext symbolType = navigator.GetPointerContext(LogicalDirection.Forward); 
                switch (symbolType)
                { 
                    case TextPointerContext.Text: 
                        string text = navigator.GetTextInRun(LogicalDirection.Forward);
                        string nexText = text.Replace(doubleAccessKeyMarker, accessKeyMarker); 
                        if (text != nexText)
                        {
                            TextPointer keyStart = new TextPointer(navigator, 0);
                            TextPointer keyEnd = new TextPointer(navigator, text.Length); 

                            UninitializeTextContainerListener(); 
                            TextContainer.BeginChange(); 
                            try
                            { 
                                keyEnd.InsertTextInRun(nexText);
                                TextRangeEdit.DeleteInlineContent(keyStart, keyEnd);
                            }
                            finally 
                            {
                                TextContainer.EndChange(); 
                                InitializeTextContainerListener(); 
                            }
                        } 

                        break;
                }
                navigator.MoveToNextContextPosition(LogicalDirection.Forward); 
            }
        } 
 
        // Returns the index of _ marker.
        // _ can be escaped by double _ 
        private static int FindAccessKeyMarker(string text)
        {
            int lenght = text.Length;
            int startIndex = 0; 
            while (startIndex < lenght)
            { 
                int index = text.IndexOf(AccessKeyMarker, startIndex); 
                if (index == -1)
                    return -1; 
                // If next char exist and different from _
                if (index + 1 < lenght && text[index + 1] != AccessKeyMarker)
                    return index;
                startIndex = index + 2; 
            }
 
            return -1; 
        }
 
        internal static string RemoveAccessKeyMarker(string text)
        {
            if (!string.IsNullOrEmpty(text))
            { 
                int index = FindAccessKeyMarker(text);
                if (index >=0 && index < text.Length - 1) 
                    return text.Remove(index, 1); 
            }
            return text; 
        }

        private void RegisterAccessKey()
        { 
            if (_currentlyRegistered != null)
            { 
                AccessKeyManager.Unregister(_currentlyRegistered, this); 
                _currentlyRegistered = null;
            } 
            string key = _accessKey.Text;
            if (!string.IsNullOrEmpty(key))
            {
                AccessKeyManager.Register(key, this); 
                _currentlyRegistered = key;
            } 
        } 

        //------------------------------------------------------------------- 
        // Text helpers
        //-------------------------------------------------------------------
        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ((AccessText) d).UpdateText((string) e.NewValue);
        } 
 
        private void UpdateText(string text)
        { 
            if (text == null)
                text = string.Empty;

            _accessKeyLocated = false; 
            _accessKey = null;
            TextContainer.BeginChange(); 
            try 
            {
                TextContainer.DeleteContentInternal((TextPointer)TextContainer.Start, TextContainer.End); 
                Run run = Inline.CreateImplicitRun(this);
                ((TextPointer)TextContainer.End).InsertTextElement(run);
                run.Text = text;
            } 
            finally
            { 
                TextContainer.EndChange(); 
            }
        } 

        // ------------------------------------------------------------------
        // Setup event handler.
        // ----------------------------------------------------------------- 
        private void InitializeTextContainerListener()
        { 
            TextContainer.Changed += new TextContainerChangedEventHandler(OnTextContainerChanged); 
        }
 
        // ------------------------------------------------------------------
        // Clear event handler.
        // ------------------------------------------------------------------
        private void UninitializeTextContainerListener() 
        {
            TextContainer.Changed -= new TextContainerChangedEventHandler(OnTextContainerChanged); 
        } 

        // ----------------------------------------------------------------- 
        // Handler for TextContainer.Changed notification.
        // ------------------------------------------------------------------
        private void OnTextContainerChanged(object sender, TextContainerChangedEventArgs args)
        { 
            // Skip changes that only affect properties.
            if (args.HasContentAddedOrRemoved) 
            { 
                UpdateAccessKey();
            } 
        }

        #endregion Private methods
 
        //-------------------------------------------------------------------
        // 
        //  Private Fields 
        //
        //------------------------------------------------------------------- 

        #region Private Fields

        //--------------------------------------------------------------- 
        // Text container for actual content
        //---------------------------------------------------------------- 
        private TextContainer _textContainer; 

        //--------------------------------------------------------------- 
        // Visual tree text block
        //----------------------------------------------------------------
        private TextBlock _textBlock;
 
        //----------------------------------------------------------------
        // Visual tree Run - created internally if _ is found 
        //--------------------------------------------------------------- 
        private Run _accessKey;
 
        //----------------------------------------------------------------
        // Flag indicating whether the access key element has been located
        //---------------------------------------------------------------
        private bool _accessKeyLocated; 

        //--------------------------------------------------------------- 
        // Defines the charecter to be used in fron of the access key 
        //---------------------------------------------------------------
        private const char _accessKeyMarker = '_'; 

        //----------------------------------------------------------------
        // Stores the default Style applied on the internal Run
        //--------------------------------------------------------------- 
        private static Style _accessKeyStyle;
 
        //---------------------------------------------------------------- 
        // Flag that indicates if access key is registered with this AccessText
        //---------------------------------------------------------------- 
        private string _currentlyRegistered;

        //---------------------------------------------------------------
        // Flag that indicates that internal Run should have a custom serialization 
        //----------------------------------------------------------------
        private static readonly UncommonField HasCustomSerializationStorage = new UncommonField(); 
 
        #endregion Private Fields
    } 
}


 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 
using System.Collections;
using System.ComponentModel; 
using System.Windows.Data; 
using System.Windows.Documents;
using System.Windows.Input; 
using System.Windows.Media;
using System.Windows.Markup;
using System.Diagnostics;
using System.Xml; 

using MS.Internal; 
 
namespace System.Windows.Controls
{ 
    /// 
    /// AccessText Element - Register an accesskey specified after the underscore character in the text.
    /// 
    [ContentProperty("Text")] 
    public class AccessText : FrameworkElement, IAddChild
    { 
        //------------------------------------------------------------------- 
        //
        //  IContentHost Members 
        //
        //-------------------------------------------------------------------

        #region IAddChild members 

        /// 
        /// Called to Add the object as a Child. 
        ///
        /// 
        /// Object to add as a child
        ///
        void IAddChild.AddChild(Object value)
        { 
            ((IAddChild)TextBlock).AddChild(value);
        } 
 
        ///
        /// Called when text appears under the tag in markup. 
        ///
        ///
        /// Text to Add to the Object
        /// 
        void IAddChild.AddText(string text)
        { 
            ((IAddChild)TextBlock).AddText(text); 
        }
 
        #endregion IAddChild members

        //--------------------------------------------------------------------
        // 
        //  LogicalTree
        // 
        //------------------------------------------------------------------- 

        #region LogicalTree 

        /// 
        /// Returns enumerator to logical children.
        ///  
        protected internal override IEnumerator LogicalChildren
        { 
            get 
            {
                return new RangeContentEnumerator(TextContainer.Start, TextContainer.End); 
            }
        }

        #endregion LogicalTree 

        //-------------------------------------------------------------------- 
        // 
        //  Constructors
        // 
        //--------------------------------------------------------------------

        #region Constructors
 
        /// 
        /// AccessText constructor. 
        ///  
        public AccessText() : base()
        { 
        }

        #endregion Constructors
 
        //-------------------------------------------------------------------
        // 
        //  Public Properties 
        //
        //-------------------------------------------------------------------- 

        #region Public Properties

        ///  
        ///     Read only access to the key after the first underline character
        ///  
        public char AccessKey 
        {
            get 
            {
                //
                return (_accessKey != null && _accessKey.Text.Length > 0) ? _accessKey.Text[0] : (char)0;
            } 
        }
 
        #endregion Public Properties 

        //------------------------------------------------------------------- 
        //
        //  Public Dynamic Properties
        //
        //------------------------------------------------------------------- 

        #region Public Dynamic Properties 
 
        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty TextProperty =
                DependencyProperty.Register(
                        "Text", 
                        typeof(string),
                        typeof(AccessText), 
                        new FrameworkPropertyMetadata( 
                                string.Empty,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, 
                                new PropertyChangedCallback(OnTextChanged)));

        /// 
        /// The Text property defines the text to be displayed. 
        /// 
        [DefaultValue("")] 
        public string Text 
        {
            get { return (string) GetValue(TextProperty); } 
            set { SetValue(TextProperty, value); }
        }

 
        /// 
        /// DependencyProperty for  property. 
        ///  
        public static readonly DependencyProperty FontFamilyProperty =
                TextElement.FontFamilyProperty.AddOwner(typeof(AccessText)); 

        /// 
        /// The FontFamily property specifies the name of font family.
        ///  
        [Localizability(
            LocalizationCategory.Font, 
            Modifiability = Modifiability.Unmodifiable 
        )]
        public FontFamily FontFamily 
        {
            get { return (FontFamily) GetValue(FontFamilyProperty); }
            set { SetValue(FontFamilyProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty FontStyleProperty = 
                TextElement.FontStyleProperty.AddOwner(typeof(AccessText));

        /// 
        /// The FontStyle property requests normal, italic, and oblique faces within a font family. 
        /// 
        public FontStyle FontStyle 
        { 
            get { return (FontStyle) GetValue(FontStyleProperty); }
            set { SetValue(FontStyleProperty, value); } 
        }

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty FontWeightProperty = 
                TextElement.FontWeightProperty.AddOwner(typeof(AccessText)); 

        ///  
        /// The FontWeight property specifies the weight of the font.
        /// 
        public FontWeight FontWeight
        { 
            get { return (FontWeight) GetValue(FontWeightProperty); }
            set { SetValue(FontWeightProperty, value); } 
        } 

        ///  
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty FontStretchProperty =
                TextElement.FontStretchProperty.AddOwner(typeof(AccessText)); 

        ///  
        /// The FontStretch property selects a normal, condensed, or extended face from a font family. 
        /// 
        public FontStretch FontStretch 
        {
            get { return (FontStretch) GetValue(FontStretchProperty); }
            set { SetValue(FontStretchProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty FontSizeProperty = 
                TextElement.FontSizeProperty.AddOwner(typeof(AccessText));

        /// 
        /// The FontSize property specifies the size of the font. 
        /// 
        [TypeConverter(typeof(FontSizeConverter))] 
        [Localizability(LocalizationCategory.None)] 
        public double FontSize
        { 
            get { return (double) GetValue(FontSizeProperty); }
            set { SetValue(FontSizeProperty, value); }
        }
 
        /// 
        /// DependencyProperty for  property. 
        ///  
        public static readonly DependencyProperty ForegroundProperty =
                TextElement.ForegroundProperty.AddOwner(typeof(AccessText)); 

        /// 
        /// The Foreground property specifies the foreground brush of an element's text content.
        ///  
        public Brush Foreground
        { 
            get { return (Brush) GetValue(ForegroundProperty); } 
            set { SetValue(ForegroundProperty, value); }
        } 

        /// 
        /// DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty BackgroundProperty =
                TextElement.BackgroundProperty.AddOwner( 
                        typeof(AccessText), 
                        new FrameworkPropertyMetadata(
                                null, 
                                FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged)));

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

        ///  
        /// DependencyProperty for  property.
        ///  
        public static readonly DependencyProperty TextDecorationsProperty = 
                Inline.TextDecorationsProperty.AddOwner(
                        typeof(AccessText), 
                        new FrameworkPropertyMetadata(
                                new FreezableDefaultValueFactory(TextDecorationCollection.Empty),
                                FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged))); 

        ///  
        /// The TextDecorations property specifies decorations that are added to the text of an element. 
        /// 
        public TextDecorationCollection TextDecorations 
        {
            get { return (TextDecorationCollection) GetValue(TextDecorationsProperty); }
            set { SetValue(TextDecorationsProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty TextEffectsProperty = 
                TextElement.TextEffectsProperty.AddOwner(
                        typeof(AccessText),
                        new FrameworkPropertyMetadata(
                                new FreezableDefaultValueFactory(TextEffectCollection.Empty), 
                                FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged))); 
 
        /// 
        /// The TextEffects property specifies effects that are added to the text of an element. 
        /// 
        public TextEffectCollection TextEffects
        {
            get { return (TextEffectCollection) GetValue(TextEffectsProperty); } 
            set { SetValue(TextEffectsProperty, value); }
        } 
 
        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty LineHeightProperty =
                Block.LineHeightProperty.AddOwner(typeof(AccessText));
 
        /// 
        /// The LineHeight property specifies the height of each generated line box. 
        ///  
        [TypeConverter(typeof(LengthConverter))]
        public double LineHeight 
        {
            get { return (double) GetValue(LineHeightProperty); }
            set { SetValue(LineHeightProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty LineStackingStrategyProperty = 
                Block.LineStackingStrategyProperty.AddOwner(typeof(AccessText));

        /// 
        /// The LineStackingStrategy property specifies how lines are placed 
        /// 
        public LineStackingStrategy LineStackingStrategy 
        { 
            get { return (LineStackingStrategy)GetValue(LineStackingStrategyProperty); }
            set { SetValue(LineStackingStrategyProperty, value); } 
        }

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty TextAlignmentProperty = 
                Block.TextAlignmentProperty.AddOwner(typeof(AccessText)); 

        ///  
        /// The TextAlignment property specifies horizontal alignment of the content.
        /// 
        public TextAlignment TextAlignment
        { 
            get { return (TextAlignment) GetValue(TextAlignmentProperty); }
            set { SetValue(TextAlignmentProperty, value); } 
        } 

        ///  
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty TextTrimmingProperty =
                TextBlock.TextTrimmingProperty.AddOwner( 
                        typeof(AccessText),
                        new FrameworkPropertyMetadata( 
                                TextTrimming.None, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged))); 

        /// 
        /// The TextTrimming property specifies the trimming behavior situation
        /// in case of clipping some textual content caused by overflowing the line's box. 
        /// 
        public TextTrimming TextTrimming 
        { 
            get { return (TextTrimming) GetValue(TextTrimmingProperty); }
            set { SetValue(TextTrimmingProperty, value); } 
        }

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty TextWrappingProperty = 
                TextBlock.TextWrappingProperty.AddOwner( 
                        typeof(AccessText),
                        new FrameworkPropertyMetadata( 
                                TextWrapping.NoWrap,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
                                new PropertyChangedCallback(OnPropertyChanged)));
 
        /// 
        /// The TextWrapping property controls whether or not text wraps 
        /// when it reaches the flow edge of its containing block box. 
        /// 
        public TextWrapping TextWrapping 
        {
            get { return (TextWrapping) GetValue(TextWrappingProperty); }
            set { SetValue(TextWrappingProperty, value); }
        } 

        ///  
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty BaselineOffsetProperty = 
                TextBlock.BaselineOffsetProperty.AddOwner(typeof(AccessText), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnPropertyChanged)));

        /// 
        /// The BaselineOffset property provides an adjustment to baseline offset 
        /// 
        public double BaselineOffset 
        { 
            get { return (double) GetValue(BaselineOffsetProperty); }
            set { SetValue(BaselineOffsetProperty, value); } 
        }

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

        #region Protected Methods

        ///  
        /// Content measurement.
        ///  
        /// Constraint size. 
        /// Computed desired size.
        protected sealed override Size MeasureOverride(Size constraint) 
        {
            TextBlock.Measure(constraint);
            return TextBlock.DesiredSize;
        } 

        ///  
        /// Content arrangement. 
        /// 
        /// Size that element should use to arrange itself and its children. 
        protected sealed override Size ArrangeOverride(Size arrangeSize)
        {
            TextBlock.Arrange(new Rect(arrangeSize));
            return arrangeSize; 
        }
 
        #endregion Protected Methods 

        //------------------------------------------------------------------- 
        //
        //  Internal Methods
        //
        //-------------------------------------------------------------------- 

        #region Internal Methods 
 
        internal static bool HasCustomSerialization(object o)
        { 
            Run accessKey = o as Run;
            return accessKey != null && HasCustomSerializationStorage.GetValue(accessKey);
        }
 
        #endregion Internal methods
 
        //-------------------------------------------------------------------- 
        //
        //  Internal Properties 
        //
        //-------------------------------------------------------------------

        #region Internal Properties 

        internal TextBlock TextBlock 
        { 
            get
            { 
                if (_textBlock == null)
                    CreateTextBlock();
                return _textBlock;
            } 
        }
 
 
        internal static char AccessKeyMarker
        { 
            get { return _accessKeyMarker; }
        }

        #endregion Internal Properties 

        //-------------------------------------------------------------------- 
        // 
        //  Private Methods
        // 
        //-------------------------------------------------------------------

        #region Private Methods
 
        private TextContainer TextContainer
        { 
            get 
            {
                if (_textContainer == null) 
                    CreateTextBlock();
                return _textContainer;
            }
        } 

        private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
            ((AccessText)d).TextBlock.SetValue(e.Property, e.NewValue);
        } 

        /// 
        /// CreateTextBlock - Creates a text block, adds as visual child, databinds properties and sets up appropriate event listener.
        ///  
        private void CreateTextBlock()
        { 
            _textContainer = new TextContainer(this, false /* plainTextOnly */); 
            _textBlock = new TextBlock();
            AddVisualChild(_textBlock); 
            _textBlock.IsContentPresenterContainer = true;
            _textBlock.SetTextContainer(_textContainer);
            InitializeTextContainerListener();
        } 

        ///  
        /// Gets the Visual children count of the AccessText control. 
        /// 
        protected override int VisualChildrenCount 
        {
            get { return 1; }
        }
 
        /// 
        /// Gets the Visual child at the specified index. 
        ///  
        protected override Visual GetVisualChild(int index)
        { 
            if (index != 0)
            {
                throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
            } 
            return TextBlock;
        } 
 
        // Provides custom serialization for this element
        internal static void SerializeCustom(XmlWriter xmlWriter, object o) 
        {
            Run inlineScope = o as Run;
            if (inlineScope != null)
            { 
                xmlWriter.WriteString(AccessKeyMarker + inlineScope.Text);
            } 
        } 

        private static Style AccessKeyStyle 
        {
            get
            {
                if (_accessKeyStyle == null) 
                {
                    Style accessKeyStyle = new Style(typeof(Run)); 
                    Trigger trigger = new Trigger(); 
                    trigger.Property = KeyboardNavigation.ShowKeyboardCuesProperty;
                    trigger.Value = true; 
                    trigger.Setters.Add(new Setter(TextDecorationsProperty, System.Windows.TextDecorations.Underline));
                    accessKeyStyle.Triggers.Add(trigger);
                    accessKeyStyle.Seal();
                    _accessKeyStyle = accessKeyStyle; 
                }
                return _accessKeyStyle; 
            } 
        }
 
        /// 
        /// UpdateAccessKey - Scans forward in the tree looking for the access key marker, replacing it with access key element. We only support one find.
        /// 
        private void UpdateAccessKey() 
        {
            TextPointer navigator = new TextPointer(TextContainer.Start); 
 
            while (!_accessKeyLocated && navigator.CompareTo(TextContainer.End) < 0 )
            { 
                TextPointerContext symbolType = navigator.GetPointerContext(LogicalDirection.Forward);
                switch (symbolType)
                {
                    case TextPointerContext.Text: 
                        string text = navigator.GetTextInRun(LogicalDirection.Forward);
                        int index = FindAccessKeyMarker(text); 
                        if(index != -1 && index < text.Length - 1) 
                        {
                            TextPointer keyStart = navigator.GetPositionAtOffset(index + 1); 
                            TextPointer keyEnd = keyStart.GetNextInsertionPosition(LogicalDirection.Forward);
                            int accessKeyLength = keyStart.GetOffsetToPosition(keyEnd);

                            _accessKey = new Run(text.Substring(index + 1, accessKeyLength)); 
                            _accessKey.Style = AccessKeyStyle;
 
                            RegisterAccessKey(); 

                            HasCustomSerializationStorage.SetValue(_accessKey, true); 
                            _accessKeyLocated = true;

                            UninitializeTextContainerListener();
 
                            TextContainer.BeginChange();
                            try 
                            { 
                                TextPointer underlineStart = new TextPointer(navigator, index);
                                TextRangeEdit.DeleteInlineContent(underlineStart, keyEnd); 
                                _accessKey.RepositionWithContent(underlineStart);

                            }
                            finally 
                            {
                                TextContainer.EndChange(); 
                                InitializeTextContainerListener(); 
                            }
                        } 

                        break;
                }
                navigator.MoveToNextContextPosition(LogicalDirection.Forward); 
            }
 
            // Convert double _ to single _ 
            navigator = new TextPointer(TextContainer.Start);
            string accessKeyMarker = AccessKeyMarker.ToString(); 
            string doubleAccessKeyMarker = accessKeyMarker + accessKeyMarker;
            while (navigator.CompareTo(TextContainer.End) < 0)
            {
                TextPointerContext symbolType = navigator.GetPointerContext(LogicalDirection.Forward); 
                switch (symbolType)
                { 
                    case TextPointerContext.Text: 
                        string text = navigator.GetTextInRun(LogicalDirection.Forward);
                        string nexText = text.Replace(doubleAccessKeyMarker, accessKeyMarker); 
                        if (text != nexText)
                        {
                            TextPointer keyStart = new TextPointer(navigator, 0);
                            TextPointer keyEnd = new TextPointer(navigator, text.Length); 

                            UninitializeTextContainerListener(); 
                            TextContainer.BeginChange(); 
                            try
                            { 
                                keyEnd.InsertTextInRun(nexText);
                                TextRangeEdit.DeleteInlineContent(keyStart, keyEnd);
                            }
                            finally 
                            {
                                TextContainer.EndChange(); 
                                InitializeTextContainerListener(); 
                            }
                        } 

                        break;
                }
                navigator.MoveToNextContextPosition(LogicalDirection.Forward); 
            }
        } 
 
        // Returns the index of _ marker.
        // _ can be escaped by double _ 
        private static int FindAccessKeyMarker(string text)
        {
            int lenght = text.Length;
            int startIndex = 0; 
            while (startIndex < lenght)
            { 
                int index = text.IndexOf(AccessKeyMarker, startIndex); 
                if (index == -1)
                    return -1; 
                // If next char exist and different from _
                if (index + 1 < lenght && text[index + 1] != AccessKeyMarker)
                    return index;
                startIndex = index + 2; 
            }
 
            return -1; 
        }
 
        internal static string RemoveAccessKeyMarker(string text)
        {
            if (!string.IsNullOrEmpty(text))
            { 
                int index = FindAccessKeyMarker(text);
                if (index >=0 && index < text.Length - 1) 
                    return text.Remove(index, 1); 
            }
            return text; 
        }

        private void RegisterAccessKey()
        { 
            if (_currentlyRegistered != null)
            { 
                AccessKeyManager.Unregister(_currentlyRegistered, this); 
                _currentlyRegistered = null;
            } 
            string key = _accessKey.Text;
            if (!string.IsNullOrEmpty(key))
            {
                AccessKeyManager.Register(key, this); 
                _currentlyRegistered = key;
            } 
        } 

        //------------------------------------------------------------------- 
        // Text helpers
        //-------------------------------------------------------------------
        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ((AccessText) d).UpdateText((string) e.NewValue);
        } 
 
        private void UpdateText(string text)
        { 
            if (text == null)
                text = string.Empty;

            _accessKeyLocated = false; 
            _accessKey = null;
            TextContainer.BeginChange(); 
            try 
            {
                TextContainer.DeleteContentInternal((TextPointer)TextContainer.Start, TextContainer.End); 
                Run run = Inline.CreateImplicitRun(this);
                ((TextPointer)TextContainer.End).InsertTextElement(run);
                run.Text = text;
            } 
            finally
            { 
                TextContainer.EndChange(); 
            }
        } 

        // ------------------------------------------------------------------
        // Setup event handler.
        // ----------------------------------------------------------------- 
        private void InitializeTextContainerListener()
        { 
            TextContainer.Changed += new TextContainerChangedEventHandler(OnTextContainerChanged); 
        }
 
        // ------------------------------------------------------------------
        // Clear event handler.
        // ------------------------------------------------------------------
        private void UninitializeTextContainerListener() 
        {
            TextContainer.Changed -= new TextContainerChangedEventHandler(OnTextContainerChanged); 
        } 

        // ----------------------------------------------------------------- 
        // Handler for TextContainer.Changed notification.
        // ------------------------------------------------------------------
        private void OnTextContainerChanged(object sender, TextContainerChangedEventArgs args)
        { 
            // Skip changes that only affect properties.
            if (args.HasContentAddedOrRemoved) 
            { 
                UpdateAccessKey();
            } 
        }

        #endregion Private methods
 
        //-------------------------------------------------------------------
        // 
        //  Private Fields 
        //
        //------------------------------------------------------------------- 

        #region Private Fields

        //--------------------------------------------------------------- 
        // Text container for actual content
        //---------------------------------------------------------------- 
        private TextContainer _textContainer; 

        //--------------------------------------------------------------- 
        // Visual tree text block
        //----------------------------------------------------------------
        private TextBlock _textBlock;
 
        //----------------------------------------------------------------
        // Visual tree Run - created internally if _ is found 
        //--------------------------------------------------------------- 
        private Run _accessKey;
 
        //----------------------------------------------------------------
        // Flag indicating whether the access key element has been located
        //---------------------------------------------------------------
        private bool _accessKeyLocated; 

        //--------------------------------------------------------------- 
        // Defines the charecter to be used in fron of the access key 
        //---------------------------------------------------------------
        private const char _accessKeyMarker = '_'; 

        //----------------------------------------------------------------
        // Stores the default Style applied on the internal Run
        //--------------------------------------------------------------- 
        private static Style _accessKeyStyle;
 
        //---------------------------------------------------------------- 
        // Flag that indicates if access key is registered with this AccessText
        //---------------------------------------------------------------- 
        private string _currentlyRegistered;

        //---------------------------------------------------------------
        // Flag that indicates that internal Run should have a custom serialization 
        //----------------------------------------------------------------
        private static readonly UncommonField HasCustomSerializationStorage = new UncommonField(); 
 
        #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