Browse Source

MaskedTextBox: Fix the bug where control characters would clear the selected text.

pull/1645/head
Nebuleux_cp 15 years ago
parent
commit
e2673d5001
  1. 7
      ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/Samples.Modules.Text.csproj
  2. 1
      ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/TextModule.cs
  3. 85
      ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/Views/MaskedTextBoxView.xaml
  4. 35
      ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/Views/MaskedTextBoxView.xaml.cs
  5. 2
      ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/Views/NavigationView.xaml
  6. 340
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/MaskedTextBox/Implementation/MaskedTextBox.cs

7
ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/Samples.Modules.Text.csproj

@ -78,6 +78,9 @@
<Compile Include="Views\HomeView.xaml.cs">
<DependentUpon>HomeView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\MaskedTextBoxView.xaml.cs">
<DependentUpon>MaskedTextBoxView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\NavigationView.xaml.cs">
<DependentUpon>NavigationView.xaml</DependentUpon>
</Compile>
@ -109,6 +112,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\MaskedTextBoxView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\NavigationView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

1
ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/TextModule.cs

@ -39,6 +39,7 @@ namespace Samples.Modules.Text
protected override void RegisterViewsAndTypes()
{
Container.RegisterNavigationType( typeof( HomeView ) );
Container.RegisterNavigationType( typeof( MaskedTextBoxView ) );
Container.RegisterNavigationType( typeof( WatermarkTextBoxView ) );
}
}

85
ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/Views/MaskedTextBoxView.xaml

@ -0,0 +1,85 @@
<!--*********************************************************************
Extended WPF Toolkit
Copyright (C) 2010-2012 Xceed Software Inc.
This program is provided to you under the terms of the Microsoft Reciprocal
License (Ms-RL) as published at http://wpftoolkit.codeplex.com/license
This program can be provided to you by Xceed Software Inc. under a
proprietary commercial license agreement for use in non-Open Source
projects. The commercial version of Extended WPF Toolkit also includes
priority technical support, commercial updates, and many additional
useful WPF controls if you license Xceed Business Suite for WPF.
Visit http://xceed.com and follow @datagrid on Twitter.
********************************************************************-->
<infControls:DemoView x:Class="Samples.Modules.Text.Views.MaskedTextBoxView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:infControls="clr-namespace:Samples.Infrastructure.Controls;assembly=Samples.Infrastructure"
xmlns:extToolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit/extended"
Title="MaskedTextBox">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="The MaskedTextBox control lets you display and edit values based on a mask."
TextWrapping="Wrap" />
<GroupBox Header="Features" Grid.Row="1" Margin="5">
<StackPanel Margin="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Include literals:" VerticalAlignment="Center" Margin="2" />
<CheckBox x:Name="_literals" Grid.Column="1" VerticalAlignment="Center" Margin="5" />
<TextBlock Text="Include prompt:" Grid.Row="1" VerticalAlignment="Center" Margin="2" />
<CheckBox x:Name="_prompt" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Margin="5" />
</Grid>
<Grid Margin="0,5,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Mask:" VerticalAlignment="Center" Margin="2" />
<TextBox x:Name="_mask" Grid.Column="1" VerticalAlignment="Center" Margin="5" Text="(000) 000-0000" />
<TextBlock Text="Value:" Grid.Row="1" VerticalAlignment="Center" Margin="2" />
<TextBox x:Name="_value" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Margin="5" Text="1234567890" />
<TextBlock Text="Text:" Grid.Row="2" VerticalAlignment="Center" Margin="2" />
<TextBox x:Name="_text" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" Margin="5" />
</Grid>
</StackPanel>
</GroupBox>
<StackPanel Grid.Row="2" Margin="10">
<extToolkit:MaskedTextBox IncludeLiterals="{Binding IsChecked, ElementName=_literals, Mode=TwoWay}"
IncludePrompt="{Binding IsChecked, ElementName=_prompt, Mode=TwoWay}"
Mask="{Binding Text, ElementName=_mask}"
Value="{Binding Text, ElementName=_value, Mode=TwoWay}"
Text="{Binding Text, ElementName=_text, Mode=TwoWay}" />
</StackPanel>
</Grid>
</infControls:DemoView>

35
ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/Views/MaskedTextBoxView.xaml.cs

@ -0,0 +1,35 @@
/************************************************************************
Extended WPF Toolkit
Copyright (C) 2010-2012 Xceed Software Inc.
This program is provided to you under the terms of the Microsoft Reciprocal
License (Ms-RL) as published at http://wpftoolkit.codeplex.com/license
This program can be provided to you by Xceed Software Inc. under a
proprietary commercial license agreement for use in non-Open Source
projects. The commercial version of Extended WPF Toolkit also includes
priority technical support, commercial updates, and many additional
useful WPF controls if you license Xceed Business Suite for WPF.
Visit http://xceed.com and follow @datagrid on Twitter.
**********************************************************************/
using Microsoft.Practices.Prism.Regions;
using Samples.Infrastructure.Controls;
namespace Samples.Modules.Text.Views
{
/// <summary>
/// Interaction logic for MaskedTextBoxView.xaml
/// </summary>
[RegionMemberLifetime( KeepAlive = false )]
public partial class MaskedTextBoxView : DemoView
{
public MaskedTextBoxView()
{
InitializeComponent();
}
}
}

2
ExtendedWPFToolkitSolution/Src/Samples/Modules/Samples.Modules.Text/Views/NavigationView.xaml

@ -26,7 +26,7 @@
<Style TargetType="views:NavigationView" BasedOn="{StaticResource {x:Type TreeViewItem}}" />
</TreeViewItem.Resources>
<TreeViewItem Header="MaskedTextBox" />
<TreeViewItem Header="MaskedTextBox" Tag="{x:Type views:MaskedTextBoxView}" />
<TreeViewItem Header="MultiLineTextEditor" />
<TreeViewItem Header="RichTextBox" />
<TreeViewItem Header="WatermarkTextBox" Tag="{x:Type views:WatermarkTextBoxView}" />

340
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/MaskedTextBox/Implementation/MaskedTextBox.cs

@ -128,7 +128,7 @@ namespace Microsoft.Windows.Controls
protected virtual void OnMaskChanged( string oldValue, string newValue )
{
ResolveMaskProvider( newValue );
UpdateText( MaskProvider, 0 );
UpdateText( 0 );
}
#endregion //Mask
@ -271,9 +271,6 @@ namespace Microsoft.Windows.Controls
public MaskedTextBox()
{
PreviewTextInput += TextBox_PreviewTextInput;
PreviewKeyDown += TextBox_PreviewKeyDown;
CommandBindings.Add( new CommandBinding( ApplicationCommands.Paste, Paste ) ); //handle paste
CommandBindings.Add( new CommandBinding( ApplicationCommands.Cut, null, CanCut ) ); //surpress cut
}
@ -286,7 +283,7 @@ namespace Microsoft.Windows.Controls
{
base.OnApplyTemplate();
UpdateText( MaskProvider, 0 );
UpdateText( 0 );
}
protected override void OnInitialized( EventArgs e )
@ -303,122 +300,38 @@ namespace Microsoft.Windows.Controls
protected override void OnGotKeyboardFocus( KeyboardFocusChangedEventArgs e )
{
if( SelectAllOnGotFocus )
SelectAll();
base.OnGotKeyboardFocus( e );
}
protected override void OnPreviewMouseLeftButtonDown( MouseButtonEventArgs e )
{
if( !IsKeyboardFocused )
{
e.Handled = true;
Focus();
SelectAll();
}
base.OnPreviewMouseLeftButtonDown( e );
base.OnGotKeyboardFocus( e );
}
#endregion //Base Class Overrides
#region Event Handlers
void TextBox_PreviewTextInput( object sender, TextCompositionEventArgs e )
protected override void OnPreviewKeyDown( KeyEventArgs e )
{
//if the text is readonly do not add the text
if( IsReadOnly )
{
e.Handled = true;
return;
}
e.Handled |= IsReadOnly;
int position = SelectionStart;
MaskedTextProvider provider = MaskProvider;
if( position < Text.Length )
if( !e.Handled )
{
position = GetNextCharacterPosition( position );
if( Keyboard.IsKeyToggled( Key.Insert ) )
{
if( provider.Replace( e.Text, position ) )
position++;
}
else
{
if( provider.InsertAt( e.Text, position ) )
position++;
}
position = GetNextCharacterPosition( position );
HandlePreviewKeyDown( e );
}
UpdateText( provider, position );
e.Handled = true;
base.OnPreviewTextInput( e );
base.OnPreviewKeyDown( e );
}
void TextBox_PreviewKeyDown( object sender, KeyEventArgs e )
protected override void OnPreviewTextInput( TextCompositionEventArgs e )
{
if( IsReadOnly )
return;
MaskedTextProvider provider = MaskProvider;
int position = SelectionStart;
int selectionlength = SelectionLength;
// If no selection use the start position else use end position
int endposition = ( selectionlength == 0 ) ? position : position + selectionlength - 1;
if( e.Key == Key.Delete && position < Text.Length )//handle the delete key
{
if( provider.RemoveAt( position, endposition ) )
UpdateText( provider, position );
e.Handled = true;
}
else if( e.Key == Key.Space )
{
if( provider.InsertAt( " ", position ) )
UpdateText( provider, ++position );
e.Handled = true;
}
else if( e.Key == Key.Back )//handle the back space
{
if( ( position > 0 ) && ( selectionlength == 0 ) )
{
position--;
if( provider.RemoveAt( position ) )
UpdateText( provider, position );
}
if( selectionlength != 0 )
{
if( provider.RemoveAt( position, endposition ) )
{
if( position > 0 )
position--;
UpdateText( provider, position );
}
}
e.Handled = true;
}
e.Handled |= IsReadOnly;
//if all text is selected and the user begins to type, we want to delete all selected text and continue typing the new values
//but only if the user is not tabbing / shift tabbing or copying/pasting
if( SelectionLength == Text.Length && ( e.Key != Key.Tab && e.Key != Key.LeftShift && e.Key != Key.RightShift && e.Key != Key.Left && e.Key != Key.Right && e.Key != Key.Up && e.Key != Key.Down &&
( Keyboard.Modifiers & ModifierKeys.Control ) != ModifierKeys.Control ) )
if( !e.Handled )
{
if( provider.RemoveAt( position, endposition ) )
UpdateText( provider, position );
HandlePreviewTextInput( e );
}
base.OnPreviewKeyDown( e );
base.OnPreviewTextInput( e );
}
#endregion //Event Handlers
#endregion //Base Class Overrides
#region Events
@ -441,13 +354,19 @@ namespace Microsoft.Windows.Controls
#region Private
private void UpdateText( MaskedTextProvider provider, int position )
private void UpdateText()
{
UpdateText( SelectionStart );
}
private void UpdateText( int position )
{
MaskedTextProvider provider = MaskProvider;
if( provider == null )
throw new ArgumentNullException( "MaskedTextProvider", "Mask cannot be null." );
throw new InvalidOperationException();
Text = provider.ToDisplayString();
SelectionLength = 0;
SelectionStart = position;
}
@ -552,6 +471,214 @@ namespace Microsoft.Windows.Controls
_isSyncingTextAndValueProperties = false;
}
private void HandlePreviewTextInput( TextCompositionEventArgs e )
{
this.InsertText( e.Text );
e.Handled = true;
}
private void HandlePreviewKeyDown( KeyEventArgs e )
{
if( e.Key == Key.Delete )
{
e.Handled = HandleKeyDownDelete();
}
else if( e.Key == Key.Back )
{
e.Handled = HandleKeyDownBack();
}
else if( e.Key == Key.Space )
{
InsertText( " " );
e.Handled = true;
}
else if( e.Key == Key.Return || e.Key == Key.Enter )
{
if( AcceptsReturn )
{
this.InsertText( "\r" );
}
// We don't want the OnPreviewTextInput to be triggered for the Return/Enter key
// when it is not accepted.
e.Handled = true;
}
else if( e.Key == Key.Escape )
{
// We don't want the OnPreviewTextInput to be triggered at all for the Escape key.
e.Handled = true;
}
else if( e.Key == Key.Tab )
{
if( AcceptsTab )
{
this.InsertText( "\t" );
e.Handled = true;
}
}
}
private bool HandleKeyDownDelete()
{
ModifierKeys modifiers = Keyboard.Modifiers;
bool handled = true;
if( modifiers == ModifierKeys.None )
{
if( !RemoveSelectedText() )
{
int position = SelectionStart;
if( position < Text.Length )
{
RemoveText( position, 1 );
UpdateText( position );
}
}
else
{
UpdateText();
}
}
else if( modifiers == ModifierKeys.Control )
{
if( !RemoveSelectedText() )
{
int position = SelectionStart;
RemoveTextToEnd( position );
UpdateText( position );
}
else
{
UpdateText();
}
}
else if( modifiers == ModifierKeys.Shift )
{
if( RemoveSelectedText() )
{
UpdateText();
}
else
{
handled = false;
}
}
else
{
handled = false;
}
return handled;
}
private bool HandleKeyDownBack()
{
ModifierKeys modifiers = Keyboard.Modifiers;
bool handled = true;
if( modifiers == ModifierKeys.None || modifiers == ModifierKeys.Shift )
{
if( !RemoveSelectedText() )
{
int position = SelectionStart;
if( position > 0 )
{
int newPosition = position - 1;
RemoveText( newPosition, 1 );
UpdateText( newPosition );
}
}
else
{
UpdateText();
}
}
else if( modifiers == ModifierKeys.Control )
{
if( !RemoveSelectedText() )
{
RemoveTextFromStart( SelectionStart );
UpdateText( 0 );
}
else
{
UpdateText();
}
}
else
{
handled = false;
}
return handled;
}
private void InsertText( string text )
{
int position = SelectionStart;
MaskedTextProvider provider = MaskProvider;
bool textRemoved = this.RemoveSelectedText();
position = GetNextCharacterPosition( position );
if( !textRemoved && Keyboard.IsKeyToggled( Key.Insert ) )
{
if( provider.Replace( text, position ) )
{
position += text.Length;
}
}
else
{
if( provider.InsertAt( text, position ) )
{
position += text.Length;
}
}
position = GetNextCharacterPosition( position );
this.UpdateText( position );
}
private void RemoveTextFromStart( int endPosition )
{
RemoveText( 0, endPosition );
}
private void RemoveTextToEnd( int startPosition )
{
RemoveText( startPosition, Text.Length - startPosition );
}
private void RemoveText( int position, int length )
{
if( length == 0 )
return;
MaskProvider.RemoveAt( position, position + length - 1 );
}
private bool RemoveSelectedText()
{
int length = SelectionLength;
if( length == 0 )
return false;
int position = SelectionStart;
return MaskProvider.RemoveAt( position, position + length - 1 );
}
#endregion //Private
#endregion //Methods
@ -573,7 +700,8 @@ namespace Microsoft.Windows.Controls
if( text.Length > 0 )
{
provider.Set( text );
UpdateText( provider, position );
UpdateText( position );
}
}
}

Loading…
Cancel
Save