/// <devdoc>
/// Overload to allow for passing the text when the mask is being changed from null,
/// in this case the maskedTextProvider holds backend info only (not the text).
/// </devdoc>
private void SetMaskedTextProvider( MaskedTextProvider newProvider, string textOnInitializingMask )
{
Debug.Assert( newProvider != null, "Initializing from a null MaskProvider ref." );
// Set R/W properties.
newProvider.IncludePrompt = this.maskedTextProvider.IncludePrompt;
newProvider.IncludeLiterals = this.maskedTextProvider.IncludeLiterals;
newProvider.SkipLiterals = this.maskedTextProvider.SkipLiterals;
newProvider.ResetOnPrompt = this.maskedTextProvider.ResetOnPrompt;
newProvider.ResetOnSpace = this.maskedTextProvider.ResetOnSpace;
// If mask not initialized and not initializing it, the new provider is just a property backend.
// Change won't have any effect in text.
if( this.flagState[IS_NULL_MASK] && textOnInitializingMask == null)
{
this.maskedTextProvider = newProvider;
return;
}
int testPos = 0;
bool raiseOnMaskInputRejected = false; // Raise if new provider rejects old text.
MaskedTextResultHint hint = MaskedTextResultHint.NoEffect;
MaskedTextProvider oldProvider = this.maskedTextProvider;
// Attempt to add previous text.
// If the mask is the same, we need to preserve the caret and character positions if the text is added successfully.
bool preserveCharPos = oldProvider.Mask == newProvider.Mask;
// Cache text output text before setting the new provider to determine whether we need to raise the TextChanged event.
string oldText;
// NOTE: Whenever changing the MTP, the text is lost if any character in the old text violates the new provider's mask.
if( textOnInitializingMask != null ) // Changing Mask (from null), which is the only RO property that requires passing text.
{
oldText = textOnInitializingMask;
raiseOnMaskInputRejected = !newProvider.Set( textOnInitializingMask, out testPos, out hint );
}
else
{
oldText = TextOutput;
// We need to attempt to set the input characters one by one in the edit positions so they are not
// escaped.
int assignedCount = oldProvider.AssignedEditPositionCount;
int srcPos = 0;
int dstPos = 0;
while( assignedCount > 0 )
{
srcPos = oldProvider.FindAssignedEditPositionFrom( srcPos, forward );
Debug.Assert( srcPos != MaskedTextProvider.InvalidIndex, "InvalidIndex unexpected at this time." );
if (preserveCharPos)
{
dstPos = srcPos;
}
else
{
dstPos = newProvider.FindEditPositionFrom(dstPos, forward);
if (dstPos == MaskedTextProvider.InvalidIndex)
{
newProvider.Clear();
testPos = newProvider.Length;
hint = MaskedTextResultHint.UnavailableEditPosition;
break;
}
}
if( !newProvider.Replace( oldProvider[srcPos], dstPos, out testPos, out hint ))
{
preserveCharPos = false;
newProvider.Clear();
break;
}
srcPos++;
dstPos++;
assignedCount--;
}
raiseOnMaskInputRejected = !MaskedTextProvider.GetOperationResultFromHint(hint);
}
// Set provider.
this.maskedTextProvider = newProvider;
if( this.flagState[IS_NULL_MASK] )
{
this.flagState[IS_NULL_MASK] = false;
}
// Raising events need to be done only after the new provider has been set so the MTB is in a state where properties
// can be queried from event handlers safely.
if( raiseOnMaskInputRejected )
{
OnMaskInputRejected(new MaskInputRejectedEventArgs(testPos, hint));
}
if( newProvider.IsPassword )
{
// Reset native edit control so the MaskedTextBox will take control over the characters that
// need to be replaced with the password char (the input text characters).
// MTB takes over.
SetEditControlPasswordChar('\0');
}
EventArgs e = EventArgs.Empty;
if (textOnInitializingMask != null /*changing mask from null*/ || oldProvider.Mask != newProvider.Mask)
{
OnMaskChanged(e);
}
SetWindowText(GetFormattedDisplayString(), oldText != TextOutput, preserveCharPos);
}