Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / PasswordTextContainer.cs / 1 / PasswordTextContainer.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Backing store for the PasswordBox control. // // History: // 05/14/2004 : benwest - Created. // //--------------------------------------------------------------------------- using System; using System.Windows.Threading; using System.Collections; using System.Security; using System.Diagnostics; using System.Windows.Documents; using MS.Internal; using MS.Internal.Documents; namespace System.Windows.Controls { // Backing store for the PasswordBox control. // // This TextContainer implementation is unusual in that // // - It never returns actual content through any of the abstract methods. // If you need the actual content, you must cast to PasswordTextContainer // and use the internal Password property. // // - Performance doesn't scale with large documents. The expectation is // that the document will always be small (< 100 chars). // internal sealed class PasswordTextContainer : ITextContainer { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors // Creates a new PasswordTextContainer instance. internal PasswordTextContainer(PasswordBox passwordBox) { _passwordBox = passwordBox; _password = new SecureString(); } #endregion Constructors //------------------------------------------------------ // // Internal Methods // //----------------------------------------------------- #region Internal Methods ////// Inserts text at a specified position. /// /// /// Position at which to insert the new text. /// /// /// Text to insert. /// ////// Use the CanInsertText method to determine if text may be inserted /// at position. /// /// All positions at this location are repositioned /// before or after the inserted text according to their gravity. /// internal void InsertText(ITextPointer position, string textData) { int offset; int i; BeginChange(); try { offset = ((PasswordTextPointer)position).Offset; // Strangely, there is no SecureString.InsertAt(offset, string), so // we must use a loop here. for (i = 0; i < textData.Length; i++) { _password.InsertAt(offset + i, textData[i]); } OnPasswordChange(offset, textData.Length); } finally { EndChange(); } } ////// Removes content covered by a pair of positions. /// /// /// Position preceeding the first symbol to delete. startPosition must be /// scoped by the same text element as endPosition. /// /// /// Position following the last symbol to delete. endPosition must be /// scoped by the same text element as startPosition. /// ////// Use CanDeleteContent to determine if content may be removed. /// internal void DeleteContent(ITextPointer startPosition, ITextPointer endPosition) { int startOffset; int endOffset; int i; BeginChange(); try { startOffset = ((PasswordTextPointer)startPosition).Offset; endOffset = ((PasswordTextPointer)endPosition).Offset; // Strangely, there is no SecureString.RemoveAt(offset, count), so // we must use a loop here. for (i = 0; i < endOffset - startOffset; i++) { _password.RemoveAt(startOffset); } OnPasswordChange(startOffset, startOffset - endOffset); } finally { EndChange(); } } ////// internal void BeginChange() { _changeBlockLevel++; // We'll raise the Changing event when/if we get an actual // change added, inside AddChangeSegment. } ////// internal void EndChange() { EndChange(false /* skipEvents */); } ////// internal void EndChange(bool skipEvents) { TextContainerChangedEventArgs changes; // Invariant.Assert(_changeBlockLevel > 0, "Unmatched EndChange call!"); _changeBlockLevel--; if (_changeBlockLevel == 0 && _changes != null) { changes = _changes; _changes = null; // Contact any listeners. if (this.Changed != null && !skipEvents) { Changed(this, changes); } } } ////// void ITextContainer.BeginChange() { BeginChange(); } ////// void ITextContainer.BeginChangeNoUndo() { // We don't support undo, so follow the BeginChange codepath. ((ITextContainer)this).BeginChange(); } ////// /// void ITextContainer.EndChange() { EndChange(false /* skipEvents */); } ////// void ITextContainer.EndChange(bool skipEvents) { EndChange(skipEvents); } // Allocate a new ITextPointer at the specified offset. // Equivalent to this.Start.CreatePointer(offset), but does not // necessarily allocate this.Start. ITextPointer ITextContainer.CreatePointerAtOffset(int offset, LogicalDirection direction) { return new PasswordTextPointer(this, direction, offset); } // Allocate a new ITextPointer at a specificed offset in unicode chars within the document. ITextPointer ITextContainer.CreatePointerAtCharOffset(int charOffset, LogicalDirection direction) { return ((ITextContainer)this).CreatePointerAtOffset(charOffset, direction); } ITextPointer ITextContainer.CreateDynamicTextPointer(StaticTextPointer position, LogicalDirection direction) { return ((ITextPointer)position.Handle0).CreatePointer(direction); } StaticTextPointer ITextContainer.CreateStaticPointerAtOffset(int offset) { return new StaticTextPointer(this, ((ITextContainer)this).CreatePointerAtOffset(offset, LogicalDirection.Forward)); } TextPointerContext ITextContainer.GetPointerContext(StaticTextPointer pointer, LogicalDirection direction) { return ((ITextPointer)pointer.Handle0).GetPointerContext(direction); } int ITextContainer.GetOffsetToPosition(StaticTextPointer position1, StaticTextPointer position2) { return ((ITextPointer)position1.Handle0).GetOffsetToPosition((ITextPointer)position2.Handle0); } int ITextContainer.GetTextInRun(StaticTextPointer position, LogicalDirection direction, char[] textBuffer, int startIndex, int count) { return ((ITextPointer)position.Handle0).GetTextInRun(direction, textBuffer, startIndex, count); } object ITextContainer.GetAdjacentElement(StaticTextPointer position, LogicalDirection direction) { return ((ITextPointer)position.Handle0).GetAdjacentElement(direction); } DependencyObject ITextContainer.GetParent(StaticTextPointer position) { return null; } StaticTextPointer ITextContainer.CreatePointer(StaticTextPointer position, int offset) { return new StaticTextPointer(this, ((ITextPointer)position.Handle0).CreatePointer(offset)); } StaticTextPointer ITextContainer.GetNextContextPosition(StaticTextPointer position, LogicalDirection direction) { return new StaticTextPointer(this, ((ITextPointer)position.Handle0).GetNextContextPosition(direction)); } int ITextContainer.CompareTo(StaticTextPointer position1, StaticTextPointer position2) { return ((ITextPointer)position1.Handle0).CompareTo((ITextPointer)position2.Handle0); } int ITextContainer.CompareTo(StaticTextPointer position1, ITextPointer position2) { return ((ITextPointer)position1.Handle0).CompareTo(position2); } object ITextContainer.GetValue(StaticTextPointer position, DependencyProperty formattingProperty) { return ((ITextPointer)position.Handle0).GetValue(formattingProperty); } // Adds a PasswordTextPointer to the list of live positions. // Positions in the list are updated as the document content changes. internal void AddPosition(PasswordTextPointer position) { int index; RemoveUnreferencedPositions(); if (_positionList == null) { _positionList = new ArrayList(); } index = FindIndex(position.Offset, position.LogicalDirection); _positionList.Insert(index, new WeakReference(position)); DebugAssertPositionList(); } // Removes a PasswordTextPointer from the list of live positions. // Positions in the list are updated as the document content changes. internal void RemovePosition(PasswordTextPointer searchPosition) { int index; PasswordTextPointer position; Invariant.Assert(_positionList != null); for (index = 0; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position == searchPosition) { _positionList.RemoveAt(index); // Tag index with a sentinel so we can assert below that we // did find our position... index = -1; break; } } Invariant.Assert(index == -1, "Couldn't find position to remove!"); } #endregion Internal Methods //------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ #region Internal Properties ////// Specifies whether or not the content of this PasswordTextContainer may be /// modified. /// ////// True if content may be modified, false otherwise. /// ////// Methods that modify the PasswordTextContainer, such as InsertText or /// DeleteContent, will throw InvalidOperationExceptions if this /// property returns true. /// bool ITextContainer.IsReadOnly { get { return false; } } ////// A position preceding the first symbol of this PasswordTextContainer. /// ////// The returned ITextPointer has LogicalDirection.Backward gravity. /// ITextPointer ITextContainer.Start { get { return this.Start; } } ////// A position following the last symbol of this PasswordTextContainer. /// ////// The returned ITextPointer has LogicalDirection.Forward gravity. /// ITextPointer ITextContainer.End { get { return this.End; } } ////// Autoincremented counter of content changes in this TextContainer /// uint ITextContainer.Generation { get { // return 0; } } ////// Collection of highlights applied to TextContainer content. /// Highlights ITextContainer.Highlights { get { if (_highlights == null) { _highlights = new Highlights(this); } return _highlights; } } ////// The object containing this PasswordTextContainer, from which property /// values are inherited. /// ////// May be null. /// DependencyObject ITextContainer.Parent { get { return _passwordBox; } } // Optional text selection, always null for this ITextContainer. // Since we don't use undo or annotations we don't actually need // to store the value. ITextSelection ITextContainer.TextSelection { get { // Can't invariant because debuggers like Visual Studio // will evaluate this code at runtime. //Invariant.Assert(false, "Unexpected reference to selection!"); return null; } set { // Ignore the set. } } // Optional undo manager, always null for this ITextContainer. UndoManager ITextContainer.UndoManager { get { return null; } } //0) or removed (delta < 0). private void OnPasswordChange(int offset, int delta) { PasswordTextPointer textPosition; int symbolCount; PrecursorTextChangeType operation; if (delta != 0) { UpdatePositionList(offset, delta); textPosition = new PasswordTextPointer(this, LogicalDirection.Forward, offset); if (delta > 0) { symbolCount = delta; operation = PrecursorTextChangeType.ContentAdded; } else { symbolCount = -delta; operation = PrecursorTextChangeType.ContentRemoved; } AddChange(textPosition, symbolCount, operation); } } // Scans the list of live PasswordTextPositions, updating their // state to match a change to the document. // PasswordTextPositions "float" on the content, so need to adjust // to stay with local content after an insert or delete. private void UpdatePositionList(int offset, int delta) { int index; int backwardGravitySlot; PasswordTextPointer position; if (_positionList == null) { return; } RemoveUnreferencedPositions(); // We ask for the first position at offset with Forward gravity. // This skips over all positions at offset with Backward gravity, // because we don't want to update them. index = FindIndex(offset, LogicalDirection.Forward); if (delta < 0) { // A delete. // Positions from offset to offset + -delta collapse to offset. // Track the first position index we found with Forward gravity. // As we walk along the list of positions scoped by the delete, // we'll use the index as a position to swap positions with // Backward gravity into. This ensures that when we're done // all the positions with Offset == offset are sorted such that // Backward gravity positions precede Forward gravity positions. backwardGravitySlot = -1; for (; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { // If we found a position past the scope of the change, // we can break out of this loop -- no more special cases. if (position.Offset > offset + -delta) break; // Collapse the position down to the start offset. position.Offset = offset; // If the position has backward gravity, we need to make // sure it stays sorted in our list -- positions at the // same offset are sorted such that backward gravity // positions precede forward gravity positions. if (position.LogicalDirection == LogicalDirection.Backward) { if (backwardGravitySlot >= 0) { WeakReference tempWeakReference = (WeakReference)_positionList[backwardGravitySlot]; _positionList[backwardGravitySlot] = _positionList[index]; _positionList[index] = tempWeakReference; backwardGravitySlot++; } } else if (backwardGravitySlot == -1) { // This is the first position with Forward gravity, // remember it. backwardGravitySlot = index; } } } } // Fixup all the positions to the right of the insert/delete, but // not covered by a delete. for (; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { position.Offset += delta; } } DebugAssertPositionList(); } // Scans the list of live PasswordTextPositions, looking for entries // with no references. If any are found, they are removed from the list. private void RemoveUnreferencedPositions() { int index; PasswordTextPointer position; if (_positionList == null) { return; } for (index = _positionList.Count-1; index >= 0; index--) { position = GetPointerAtIndex(index); if (position == null) { _positionList.RemoveAt(index); } } } // Returns the index of the first PasswordTextPointer with the // specified offset and gravity in the live positions list. // // If no such position exists, returns the index of the next position, // the index at which a new position with the specified offset/gravity // would be inserted. private int FindIndex(int offset, LogicalDirection gravity) { PasswordTextPointer position; int index; Invariant.Assert(_positionList != null); for (index = 0; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { if (position.Offset == offset && (position.LogicalDirection == gravity || gravity == LogicalDirection.Backward)) { break; } if (position.Offset > offset) break; } } return index; } // Debug only -- asserts the position list is in a good state. private void DebugAssertPositionList() { if (Invariant.Strict) { PasswordTextPointer position; int index; int lastOffset; LogicalDirection lastLogicalDirection; lastOffset = -1; lastLogicalDirection = LogicalDirection.Backward; for (index = 0; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { Invariant.Assert(position.Offset >= 0 && position.Offset <= _password.Length); Invariant.Assert(lastOffset <= position.Offset); if (index > 0 && position.LogicalDirection == LogicalDirection.Backward && lastOffset == position.Offset) { // Positions at the same offset should be ordered such // that Backward gravity positions preceed Forward gravity positions. Invariant.Assert(lastLogicalDirection != LogicalDirection.Forward); } lastOffset = position.Offset; lastLogicalDirection = position.LogicalDirection; } } } } // Returns a PasswordTextPointer at a given index within _positionList, // or null if the WeakReference at that index is dead. private PasswordTextPointer GetPointerAtIndex(int index) { WeakReference weakReference; object strongReference; PasswordTextPointer position; Invariant.Assert(_positionList != null); weakReference = (WeakReference)_positionList[index]; Invariant.Assert(weakReference != null); strongReference = weakReference.Target; if (strongReference != null && !(strongReference is PasswordTextPointer)) { // Diagnostics for bug 1267261. Invariant.Assert(false, "Unexpected type: " + strongReference.GetType()); } position = (PasswordTextPointer)strongReference; return position; } #if DEBUG // Debug only -- dumps the position list to the Console. // Use this method from the debugger's command window. private void DumpPositionList() { PasswordTextPointer position; int index; Debug.WriteLine(_positionList.Count + " entries."); for (index = 0; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { Debug.Write("(" + position.DebugId + ") " + position.Offset + "/" + ((position.LogicalDirection == LogicalDirection.Forward) ? "f " : "b ")); } else { Debug.Write("-/- "); } } Debug.WriteLine(""); } #endif // DEBUG #endregion Private methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // PasswordBox associated with this content. private readonly PasswordBox _passwordBox; // The TextContainer content. private SecureString _password; // List of live PasswordTextPositions. private ArrayList _positionList; // Collection of highlights applied to TextContainer content. private Highlights _highlights; // BeginChange ref count. When non-zero, we are inside a change block. private int _changeBlockLevel; // Array of pending changes in the current change block. // Null outside of a change block. private TextContainerChangedEventArgs _changes; // TextView associated with this TextContainer. private ITextView _textview; // Set true during Change event callback. // When true, modifying the TextContainer is disallowed. private bool _isReadOnly; // implementation of ITextContainer.Changing private EventHandler Changing; // implementation of ITextContainer.Change private TextContainerChangeEventHandler Change; // implementation of ITextContainer.Changed private TextContainerChangedEventHandler Changed; #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. // // // // Description: Backing store for the PasswordBox control. // // History: // 05/14/2004 : benwest - Created. // //--------------------------------------------------------------------------- using System; using System.Windows.Threading; using System.Collections; using System.Security; using System.Diagnostics; using System.Windows.Documents; using MS.Internal; using MS.Internal.Documents; namespace System.Windows.Controls { // Backing store for the PasswordBox control. // // This TextContainer implementation is unusual in that // // - It never returns actual content through any of the abstract methods. // If you need the actual content, you must cast to PasswordTextContainer // and use the internal Password property. // // - Performance doesn't scale with large documents. The expectation is // that the document will always be small (< 100 chars). // internal sealed class PasswordTextContainer : ITextContainer { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors // Creates a new PasswordTextContainer instance. internal PasswordTextContainer(PasswordBox passwordBox) { _passwordBox = passwordBox; _password = new SecureString(); } #endregion Constructors //------------------------------------------------------ // // Internal Methods // //----------------------------------------------------- #region Internal Methods ////// Inserts text at a specified position. /// /// /// Position at which to insert the new text. /// /// /// Text to insert. /// ////// Use the CanInsertText method to determine if text may be inserted /// at position. /// /// All positions at this location are repositioned /// before or after the inserted text according to their gravity. /// internal void InsertText(ITextPointer position, string textData) { int offset; int i; BeginChange(); try { offset = ((PasswordTextPointer)position).Offset; // Strangely, there is no SecureString.InsertAt(offset, string), so // we must use a loop here. for (i = 0; i < textData.Length; i++) { _password.InsertAt(offset + i, textData[i]); } OnPasswordChange(offset, textData.Length); } finally { EndChange(); } } ////// Removes content covered by a pair of positions. /// /// /// Position preceeding the first symbol to delete. startPosition must be /// scoped by the same text element as endPosition. /// /// /// Position following the last symbol to delete. endPosition must be /// scoped by the same text element as startPosition. /// ////// Use CanDeleteContent to determine if content may be removed. /// internal void DeleteContent(ITextPointer startPosition, ITextPointer endPosition) { int startOffset; int endOffset; int i; BeginChange(); try { startOffset = ((PasswordTextPointer)startPosition).Offset; endOffset = ((PasswordTextPointer)endPosition).Offset; // Strangely, there is no SecureString.RemoveAt(offset, count), so // we must use a loop here. for (i = 0; i < endOffset - startOffset; i++) { _password.RemoveAt(startOffset); } OnPasswordChange(startOffset, startOffset - endOffset); } finally { EndChange(); } } ////// internal void BeginChange() { _changeBlockLevel++; // We'll raise the Changing event when/if we get an actual // change added, inside AddChangeSegment. } ////// internal void EndChange() { EndChange(false /* skipEvents */); } ////// internal void EndChange(bool skipEvents) { TextContainerChangedEventArgs changes; // Invariant.Assert(_changeBlockLevel > 0, "Unmatched EndChange call!"); _changeBlockLevel--; if (_changeBlockLevel == 0 && _changes != null) { changes = _changes; _changes = null; // Contact any listeners. if (this.Changed != null && !skipEvents) { Changed(this, changes); } } } ////// void ITextContainer.BeginChange() { BeginChange(); } ////// void ITextContainer.BeginChangeNoUndo() { // We don't support undo, so follow the BeginChange codepath. ((ITextContainer)this).BeginChange(); } ////// /// void ITextContainer.EndChange() { EndChange(false /* skipEvents */); } ////// void ITextContainer.EndChange(bool skipEvents) { EndChange(skipEvents); } // Allocate a new ITextPointer at the specified offset. // Equivalent to this.Start.CreatePointer(offset), but does not // necessarily allocate this.Start. ITextPointer ITextContainer.CreatePointerAtOffset(int offset, LogicalDirection direction) { return new PasswordTextPointer(this, direction, offset); } // Allocate a new ITextPointer at a specificed offset in unicode chars within the document. ITextPointer ITextContainer.CreatePointerAtCharOffset(int charOffset, LogicalDirection direction) { return ((ITextContainer)this).CreatePointerAtOffset(charOffset, direction); } ITextPointer ITextContainer.CreateDynamicTextPointer(StaticTextPointer position, LogicalDirection direction) { return ((ITextPointer)position.Handle0).CreatePointer(direction); } StaticTextPointer ITextContainer.CreateStaticPointerAtOffset(int offset) { return new StaticTextPointer(this, ((ITextContainer)this).CreatePointerAtOffset(offset, LogicalDirection.Forward)); } TextPointerContext ITextContainer.GetPointerContext(StaticTextPointer pointer, LogicalDirection direction) { return ((ITextPointer)pointer.Handle0).GetPointerContext(direction); } int ITextContainer.GetOffsetToPosition(StaticTextPointer position1, StaticTextPointer position2) { return ((ITextPointer)position1.Handle0).GetOffsetToPosition((ITextPointer)position2.Handle0); } int ITextContainer.GetTextInRun(StaticTextPointer position, LogicalDirection direction, char[] textBuffer, int startIndex, int count) { return ((ITextPointer)position.Handle0).GetTextInRun(direction, textBuffer, startIndex, count); } object ITextContainer.GetAdjacentElement(StaticTextPointer position, LogicalDirection direction) { return ((ITextPointer)position.Handle0).GetAdjacentElement(direction); } DependencyObject ITextContainer.GetParent(StaticTextPointer position) { return null; } StaticTextPointer ITextContainer.CreatePointer(StaticTextPointer position, int offset) { return new StaticTextPointer(this, ((ITextPointer)position.Handle0).CreatePointer(offset)); } StaticTextPointer ITextContainer.GetNextContextPosition(StaticTextPointer position, LogicalDirection direction) { return new StaticTextPointer(this, ((ITextPointer)position.Handle0).GetNextContextPosition(direction)); } int ITextContainer.CompareTo(StaticTextPointer position1, StaticTextPointer position2) { return ((ITextPointer)position1.Handle0).CompareTo((ITextPointer)position2.Handle0); } int ITextContainer.CompareTo(StaticTextPointer position1, ITextPointer position2) { return ((ITextPointer)position1.Handle0).CompareTo(position2); } object ITextContainer.GetValue(StaticTextPointer position, DependencyProperty formattingProperty) { return ((ITextPointer)position.Handle0).GetValue(formattingProperty); } // Adds a PasswordTextPointer to the list of live positions. // Positions in the list are updated as the document content changes. internal void AddPosition(PasswordTextPointer position) { int index; RemoveUnreferencedPositions(); if (_positionList == null) { _positionList = new ArrayList(); } index = FindIndex(position.Offset, position.LogicalDirection); _positionList.Insert(index, new WeakReference(position)); DebugAssertPositionList(); } // Removes a PasswordTextPointer from the list of live positions. // Positions in the list are updated as the document content changes. internal void RemovePosition(PasswordTextPointer searchPosition) { int index; PasswordTextPointer position; Invariant.Assert(_positionList != null); for (index = 0; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position == searchPosition) { _positionList.RemoveAt(index); // Tag index with a sentinel so we can assert below that we // did find our position... index = -1; break; } } Invariant.Assert(index == -1, "Couldn't find position to remove!"); } #endregion Internal Methods //------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ #region Internal Properties ////// Specifies whether or not the content of this PasswordTextContainer may be /// modified. /// ////// True if content may be modified, false otherwise. /// ////// Methods that modify the PasswordTextContainer, such as InsertText or /// DeleteContent, will throw InvalidOperationExceptions if this /// property returns true. /// bool ITextContainer.IsReadOnly { get { return false; } } ////// A position preceding the first symbol of this PasswordTextContainer. /// ////// The returned ITextPointer has LogicalDirection.Backward gravity. /// ITextPointer ITextContainer.Start { get { return this.Start; } } ////// A position following the last symbol of this PasswordTextContainer. /// ////// The returned ITextPointer has LogicalDirection.Forward gravity. /// ITextPointer ITextContainer.End { get { return this.End; } } ////// Autoincremented counter of content changes in this TextContainer /// uint ITextContainer.Generation { get { // return 0; } } ////// Collection of highlights applied to TextContainer content. /// Highlights ITextContainer.Highlights { get { if (_highlights == null) { _highlights = new Highlights(this); } return _highlights; } } ////// The object containing this PasswordTextContainer, from which property /// values are inherited. /// ////// May be null. /// DependencyObject ITextContainer.Parent { get { return _passwordBox; } } // Optional text selection, always null for this ITextContainer. // Since we don't use undo or annotations we don't actually need // to store the value. ITextSelection ITextContainer.TextSelection { get { // Can't invariant because debuggers like Visual Studio // will evaluate this code at runtime. //Invariant.Assert(false, "Unexpected reference to selection!"); return null; } set { // Ignore the set. } } // Optional undo manager, always null for this ITextContainer. UndoManager ITextContainer.UndoManager { get { return null; } } //0) or removed (delta < 0). private void OnPasswordChange(int offset, int delta) { PasswordTextPointer textPosition; int symbolCount; PrecursorTextChangeType operation; if (delta != 0) { UpdatePositionList(offset, delta); textPosition = new PasswordTextPointer(this, LogicalDirection.Forward, offset); if (delta > 0) { symbolCount = delta; operation = PrecursorTextChangeType.ContentAdded; } else { symbolCount = -delta; operation = PrecursorTextChangeType.ContentRemoved; } AddChange(textPosition, symbolCount, operation); } } // Scans the list of live PasswordTextPositions, updating their // state to match a change to the document. // PasswordTextPositions "float" on the content, so need to adjust // to stay with local content after an insert or delete. private void UpdatePositionList(int offset, int delta) { int index; int backwardGravitySlot; PasswordTextPointer position; if (_positionList == null) { return; } RemoveUnreferencedPositions(); // We ask for the first position at offset with Forward gravity. // This skips over all positions at offset with Backward gravity, // because we don't want to update them. index = FindIndex(offset, LogicalDirection.Forward); if (delta < 0) { // A delete. // Positions from offset to offset + -delta collapse to offset. // Track the first position index we found with Forward gravity. // As we walk along the list of positions scoped by the delete, // we'll use the index as a position to swap positions with // Backward gravity into. This ensures that when we're done // all the positions with Offset == offset are sorted such that // Backward gravity positions precede Forward gravity positions. backwardGravitySlot = -1; for (; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { // If we found a position past the scope of the change, // we can break out of this loop -- no more special cases. if (position.Offset > offset + -delta) break; // Collapse the position down to the start offset. position.Offset = offset; // If the position has backward gravity, we need to make // sure it stays sorted in our list -- positions at the // same offset are sorted such that backward gravity // positions precede forward gravity positions. if (position.LogicalDirection == LogicalDirection.Backward) { if (backwardGravitySlot >= 0) { WeakReference tempWeakReference = (WeakReference)_positionList[backwardGravitySlot]; _positionList[backwardGravitySlot] = _positionList[index]; _positionList[index] = tempWeakReference; backwardGravitySlot++; } } else if (backwardGravitySlot == -1) { // This is the first position with Forward gravity, // remember it. backwardGravitySlot = index; } } } } // Fixup all the positions to the right of the insert/delete, but // not covered by a delete. for (; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { position.Offset += delta; } } DebugAssertPositionList(); } // Scans the list of live PasswordTextPositions, looking for entries // with no references. If any are found, they are removed from the list. private void RemoveUnreferencedPositions() { int index; PasswordTextPointer position; if (_positionList == null) { return; } for (index = _positionList.Count-1; index >= 0; index--) { position = GetPointerAtIndex(index); if (position == null) { _positionList.RemoveAt(index); } } } // Returns the index of the first PasswordTextPointer with the // specified offset and gravity in the live positions list. // // If no such position exists, returns the index of the next position, // the index at which a new position with the specified offset/gravity // would be inserted. private int FindIndex(int offset, LogicalDirection gravity) { PasswordTextPointer position; int index; Invariant.Assert(_positionList != null); for (index = 0; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { if (position.Offset == offset && (position.LogicalDirection == gravity || gravity == LogicalDirection.Backward)) { break; } if (position.Offset > offset) break; } } return index; } // Debug only -- asserts the position list is in a good state. private void DebugAssertPositionList() { if (Invariant.Strict) { PasswordTextPointer position; int index; int lastOffset; LogicalDirection lastLogicalDirection; lastOffset = -1; lastLogicalDirection = LogicalDirection.Backward; for (index = 0; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { Invariant.Assert(position.Offset >= 0 && position.Offset <= _password.Length); Invariant.Assert(lastOffset <= position.Offset); if (index > 0 && position.LogicalDirection == LogicalDirection.Backward && lastOffset == position.Offset) { // Positions at the same offset should be ordered such // that Backward gravity positions preceed Forward gravity positions. Invariant.Assert(lastLogicalDirection != LogicalDirection.Forward); } lastOffset = position.Offset; lastLogicalDirection = position.LogicalDirection; } } } } // Returns a PasswordTextPointer at a given index within _positionList, // or null if the WeakReference at that index is dead. private PasswordTextPointer GetPointerAtIndex(int index) { WeakReference weakReference; object strongReference; PasswordTextPointer position; Invariant.Assert(_positionList != null); weakReference = (WeakReference)_positionList[index]; Invariant.Assert(weakReference != null); strongReference = weakReference.Target; if (strongReference != null && !(strongReference is PasswordTextPointer)) { // Diagnostics for bug 1267261. Invariant.Assert(false, "Unexpected type: " + strongReference.GetType()); } position = (PasswordTextPointer)strongReference; return position; } #if DEBUG // Debug only -- dumps the position list to the Console. // Use this method from the debugger's command window. private void DumpPositionList() { PasswordTextPointer position; int index; Debug.WriteLine(_positionList.Count + " entries."); for (index = 0; index < _positionList.Count; index++) { position = GetPointerAtIndex(index); if (position != null) { Debug.Write("(" + position.DebugId + ") " + position.Offset + "/" + ((position.LogicalDirection == LogicalDirection.Forward) ? "f " : "b ")); } else { Debug.Write("-/- "); } } Debug.WriteLine(""); } #endif // DEBUG #endregion Private methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // PasswordBox associated with this content. private readonly PasswordBox _passwordBox; // The TextContainer content. private SecureString _password; // List of live PasswordTextPositions. private ArrayList _positionList; // Collection of highlights applied to TextContainer content. private Highlights _highlights; // BeginChange ref count. When non-zero, we are inside a change block. private int _changeBlockLevel; // Array of pending changes in the current change block. // Null outside of a change block. private TextContainerChangedEventArgs _changes; // TextView associated with this TextContainer. private ITextView _textview; // Set true during Change event callback. // When true, modifying the TextContainer is disallowed. private bool _isReadOnly; // implementation of ITextContainer.Changing private EventHandler Changing; // implementation of ITextContainer.Change private TextContainerChangeEventHandler Change; // implementation of ITextContainer.Changed private TextContainerChangedEventHandler Changed; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EdmTypeAttribute.cs
- CheckBoxBaseAdapter.cs
- _UriTypeConverter.cs
- columnmapfactory.cs
- CompensationTokenData.cs
- TrustManagerPromptUI.cs
- NavigationCommands.cs
- WebPartEditorApplyVerb.cs
- ModulesEntry.cs
- VerificationException.cs
- MulticastDelegate.cs
- DbDataAdapter.cs
- DesignerAttribute.cs
- GroupBoxAutomationPeer.cs
- SafeNativeMethods.cs
- ConsoleTraceListener.cs
- SettingsContext.cs
- GrammarBuilderRuleRef.cs
- EventProviderBase.cs
- DES.cs
- DesignTimeTemplateParser.cs
- KeyGestureConverter.cs
- FreezableOperations.cs
- TrackingDataItemValue.cs
- CompilationUnit.cs
- ApplicationException.cs
- FlowDocumentPage.cs
- DbMetaDataFactory.cs
- OdbcPermission.cs
- DoubleCollectionValueSerializer.cs
- JsonSerializer.cs
- ApplicationInfo.cs
- DesignerSerializationManager.cs
- dataSvcMapFileLoader.cs
- References.cs
- GotoExpression.cs
- XmlElementAttributes.cs
- DataGridViewAddColumnDialog.cs
- Animatable.cs
- ProjectionPlan.cs
- Floater.cs
- HttpChannelBindingToken.cs
- ProcessThreadCollection.cs
- SRef.cs
- SqlCommandSet.cs
- SymbolMethod.cs
- EllipseGeometry.cs
- SubMenuStyleCollection.cs
- IDQuery.cs
- SharedMemory.cs
- FileInfo.cs
- WSMessageEncoding.cs
- DataGridViewAdvancedBorderStyle.cs
- SqlConnectionHelper.cs
- DetailsViewRowCollection.cs
- UIHelper.cs
- SpellerError.cs
- MD5CryptoServiceProvider.cs
- RegistryExceptionHelper.cs
- ScrollEvent.cs
- LinkLabel.cs
- BinaryObjectWriter.cs
- WebPartDeleteVerb.cs
- ScriptBehaviorDescriptor.cs
- LeafCellTreeNode.cs
- RegionData.cs
- KeysConverter.cs
- ServiceOperationParameter.cs
- MenuItemBindingCollection.cs
- FloaterParagraph.cs
- Pen.cs
- ObjectFullSpanRewriter.cs
- SecurityContextSecurityTokenResolver.cs
- Trace.cs
- DaylightTime.cs
- CLSCompliantAttribute.cs
- DateTimeFormatInfo.cs
- ContextStaticAttribute.cs
- CreateUserWizardDesigner.cs
- DataError.cs
- SessionStateSection.cs
- ItemContainerProviderWrapper.cs
- PeerApplication.cs
- IntSecurity.cs
- StyleCollectionEditor.cs
- XmlSchemaExternal.cs
- RangeBase.cs
- MediaElementAutomationPeer.cs
- AppDomainShutdownMonitor.cs
- rsa.cs
- EmbeddedMailObject.cs
- CounterSampleCalculator.cs
- FixedSOMLineCollection.cs
- ColorTypeConverter.cs
- ObjectDataSourceSelectingEventArgs.cs
- ReaderWriterLockWrapper.cs
- AssociationType.cs
- ButtonField.cs
- HttpModuleCollection.cs
- NamedPipeConnectionPoolSettingsElement.cs