开发者

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" />
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜