TextBox caret goes wrong when changing the underlying property value
See the following example:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:WpfApplication1"
SizeToContent="WidthAndHeight">
<Window.DataContext>
<src:CodeName/>
</Window.DataContext>
<TextBox Text="{Binding Code, UpdateSourceTrigger=PropertyChanged}" />
</Window>
Imports System.ComponentModel
Public Class CodeName
Implements INotifyPropertyChanged
Private m_Code As String
Public Property Code() As String
开发者_运维问答 Get
Return m_Code
End Get
Set(ByVal value As String)
If Not String.IsNullOrWhiteSpace(value) Then value = "_" & value
m_Code = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Code"))
End Set
End Property
Public Event PropertyChanged(ByVal sender As Object,
ByVal e As PropertyChangedEventArgs) _
Implements INotifyPropertyChanged.PropertyChanged
End Class
As you can see, I am changing the edited value so that when the user enters text in the TextBox
, it's updated adding a _
to its beginning.
What happens is, that when I type 123456789
the result in the TextBox
is: _________987654321
not _________123456789
as expected.
What could be a neat way to fix it?
I don't want to my my whole code dirty with KeyUp etc. events moving the caret around. In the other hand, I do want this to be done at the entity level.Note: my 'real-life' function is formatting a phone-number with dashes, and more.
I would use the textchanged event of the textbox to move the caret to the end, like this:
<TextBox Name="textBox1" Text="{Binding Code, UpdateSourceTrigger=PropertyChanged}" TextChanged="textChangedEventHandler"/>
Private Sub textChangedEventHandler(ByVal sender As Object, ByVal args As TextChangedEventArgs)
textBox1.CaretIndex = textBox1.Text.Length
End Sub
Public Class TextBoxBehavor
Public Shared Function GetMoveCaretOnTextChange(ByVal element As TextBox) As Boolean
If element Is Nothing Then Throw New ArgumentNullException("element")
Return element.GetValue(MoveCaretOnTextChangeProperty)
End Function
Public Shared Sub SetMoveCaretOnTextChange(ByVal element As TextBox, ByVal value As Boolean)
If element Is Nothing Then Throw New ArgumentNullException("element")
element.SetValue(MoveCaretOnTextChangeProperty, value)
End Sub
Public Shared ReadOnly MoveCaretOnTextChangeProperty As DependencyProperty =
DependencyProperty.RegisterAttached("MoveCaretOnTextChange",
GetType(Boolean), GetType(TextBoxBehavior),
New FrameworkPropertyMetadata(
New PropertyChangedCallback(AddressOf MoveCaretOnTextChange_PropertyChanged)))
Private Shared Sub MoveCaretOnTextChange_PropertyChanged(ByVal sender As Object,
ByVal e As DependencyPropertyChangedEventArgs)
Dim tb = DirectCast(sender, TextBox)
Static tb_TextChanged As TextChangedEventHandler =
Sub(obj, tcea)
Dim textBox = DirectCast(obj, TextBox)
textBox.CaretIndex = textBox.Text.Length
End Sub
If CBool(e.NewValue) Then
AddHandler tb.TextChanged, tb_TextChanged
Else
RemoveHandler tb.TextChanged, tb_TextChanged
End If
End Sub
End Class
Usage:
<TextBox src:TextBoxBehavior.MoveCaretOnTextChange="True"
xmlns:src="clr-namespace:WpfApplication1" />
精彩评论