Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Controls / PasswordTextContainer.cs / 3 / PasswordTextContainer.cs
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
//
// Description: Backing store for the PasswordBox control.
//
// History:
// 05/14/2004 : [....] - 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
- TextSerializer.cs
- FamilyMap.cs
- ContentPropertyAttribute.cs
- LayoutTable.cs
- LoginUtil.cs
- HitTestParameters.cs
- CLSCompliantAttribute.cs
- TextPointerBase.cs
- SqlDataSourceSummaryPanel.cs
- SerializationAttributes.cs
- SoapFormatter.cs
- FontEmbeddingManager.cs
- TextFormatterContext.cs
- XamlGridLengthSerializer.cs
- BaseInfoTable.cs
- WebPartConnectionCollection.cs
- ArglessEventHandlerProxy.cs
- AllMembershipCondition.cs
- GlyphCollection.cs
- MenuItemBindingCollection.cs
- ToolBarOverflowPanel.cs
- AppSettings.cs
- BinHexEncoding.cs
- Validator.cs
- StylusDownEventArgs.cs
- FrameworkTextComposition.cs
- UserNamePasswordValidator.cs
- FileIOPermission.cs
- XmlComment.cs
- WorkflowServiceInstance.cs
- TextReader.cs
- BitmapEffect.cs
- CoTaskMemHandle.cs
- UserControl.cs
- ColumnResult.cs
- ToolboxBitmapAttribute.cs
- StylusPointPropertyUnit.cs
- HtmlInputControl.cs
- SqlReorderer.cs
- WebHttpBinding.cs
- StreamProxy.cs
- UnsafePeerToPeerMethods.cs
- SerializerProvider.cs
- JobPageOrder.cs
- InputScopeAttribute.cs
- UnknownWrapper.cs
- BindingMemberInfo.cs
- AttributeEmitter.cs
- DocumentApplicationJournalEntry.cs
- NavigationPropertyEmitter.cs
- DataListItemCollection.cs
- ProcessInfo.cs
- RegisteredExpandoAttribute.cs
- UncommonField.cs
- MarkupCompilePass2.cs
- ScrollBarAutomationPeer.cs
- ProfileEventArgs.cs
- SerializerWriterEventHandlers.cs
- CodeArgumentReferenceExpression.cs
- CompilerInfo.cs
- TimeManager.cs
- ForwardPositionQuery.cs
- Pkcs7Signer.cs
- CodeConstructor.cs
- HandledMouseEvent.cs
- RoutedEventArgs.cs
- SafeNativeMethods.cs
- MimeObjectFactory.cs
- MessageProperties.cs
- CounterSample.cs
- ZipIOExtraFieldZip64Element.cs
- DrawToolTipEventArgs.cs
- SqlMetaData.cs
- OdbcCommandBuilder.cs
- AdPostCacheSubstitution.cs
- FormatPage.cs
- _Rfc2616CacheValidators.cs
- GridViewRowPresenterBase.cs
- ElementUtil.cs
- AffineTransform3D.cs
- UIntPtr.cs
- SpellerInterop.cs
- AssociationEndMember.cs
- CodeArrayIndexerExpression.cs
- translator.cs
- sortedlist.cs
- DropDownList.cs
- ToolboxBitmapAttribute.cs
- ColorConverter.cs
- TemplateBuilder.cs
- RelationshipWrapper.cs
- SafeRightsManagementQueryHandle.cs
- XmlMtomWriter.cs
- RoutingExtension.cs
- SelectorItemAutomationPeer.cs
- ButtonAutomationPeer.cs
- FixedFindEngine.cs
- XmlRawWriter.cs
- Separator.cs
- XmlStringTable.cs