Cómo enlazar a la posición del cursor de CaretIndex aka de un cuadro de texto

Hola, estoy intentando enlazar con la propiedad TextBox.CaretIndex que no es una propiedad de DependencyProperty , por lo que creé un Behavior , pero no funciona como se esperaba.

Expectativa (cuando se enfoca)

  • por defecto = 0
  • si cambio el valor en mi vista , debería cambiar el valor en mi modelo de vista
  • si cambio el valor en mi viewmodel debería cambiar el valor en mi vista

Comportamiento actual

  • El valor del modelo de vista se llama a unos cuando se abre la ventana

Código detrás

 public class TextBoxBehavior : DependencyObject { public static readonly DependencyProperty CursorPositionProperty = DependencyProperty.Register( "CursorPosition", typeof(int), typeof(TextBoxBehavior), new FrameworkPropertyMetadata( default(int), new PropertyChangedCallback(CursorPositionChanged))); public static void SetCursorPosition(DependencyObject dependencyObject, int i) { // breakpoint get never called dependencyObject.SetValue(CursorPositionProperty, i); } public static int GetCursorPosition(DependencyObject dependencyObject) { // breakpoint get never called return (int)dependencyObject.GetValue(CursorPositionProperty); } private static void CursorPositionChanged( DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { // breakpoint get never called //var textBox = dependencyObject as TextBox; //if (textBox == null) return; } } 

XAML

  

Más información

Creo que hay algo realmente incorrecto aquí porque necesito derivarlo de DependencyObject que nunca se necesitó antes, porque CursorPositionProperty ya es una CursorPositionProperty DependencyProperty , por lo que debería ser suficiente. También creo que necesito usar algunos eventos en mi Behavior para configurar mi CursorPositionProperty correctamente, pero no sé cuál.

Después de luchar con mi comportamiento, puedo presentarte una solución de trabajo del 99% .

Comportamiento

 using System.Windows; using System.Windows.Controls; using System.Windows.Data; namespace WpfMVVMTextBoxCursorPosition { public class TextBoxCursorPositionBehavior : DependencyObject { public static void SetCursorPosition(DependencyObject dependencyObject, int i) { dependencyObject.SetValue(CursorPositionProperty, i); } public static int GetCursorPosition(DependencyObject dependencyObject) { return (int)dependencyObject.GetValue(CursorPositionProperty); } public static readonly DependencyProperty CursorPositionProperty = DependencyProperty.Register("CursorPosition" , typeof(int) , typeof(TextBoxCursorPositionBehavior) , new FrameworkPropertyMetadata(default(int)) { BindsTwoWayByDefault = true ,DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged } ); public static readonly DependencyProperty TrackCaretIndexProperty = DependencyProperty.RegisterAttached( "TrackCaretIndex", typeof(bool), typeof(TextBoxCursorPositionBehavior), new UIPropertyMetadata(false , OnTrackCaretIndex)); public static void SetTrackCaretIndex(DependencyObject dependencyObject, bool i) { dependencyObject.SetValue(TrackCaretIndexProperty, i); } public static bool GetTrackCaretIndex(DependencyObject dependencyObject) { return (bool)dependencyObject.GetValue(TrackCaretIndexProperty); } private static void OnTrackCaretIndex(DependencyObject dependency, DependencyPropertyChangedEventArgs e) { var textbox = dependency as TextBox; if (textbox == null) return; bool oldValue = (bool)e.OldValue; bool newValue = (bool)e.NewValue; if (!oldValue && newValue) // If changed from false to true { textbox.SelectionChanged += OnSelectionChanged; } else if (oldValue && !newValue) // If changed from true to false { textbox.SelectionChanged -= OnSelectionChanged; } } private static void OnSelectionChanged(object sender, RoutedEventArgs e) { var textbox = sender as TextBox; if (textbox != null) SetCursorPosition(textbox, textbox.CaretIndex); // dies line does nothing } } } 

XAML

    

hay algo que no sé por qué no funciona => BindsTwoWayByDefault = true . no tiene ningún efecto en el enlace en la medida en que puedo decirle que debido a esto necesito establecer el modo de enlace explícito en XAML

Como ha dicho, la propiedad TextBox.CaretIndex no es una propiedad de DependencyProperty , por lo que no puede enlazarse con ella. Incluso con su propia propiedad de DependencyProperty , no funcionará … ¿cómo esperaría que se le notifique cuando TextBox.CaretIndex propiedad TextBox.CaretIndex ?

Encontré un problema similar, y la solución más fácil para mí fue heredar de TextBox y agregar una propiedad de dependencia. Así que se ve así:

 namespace UI.Controls { public class MyTextBox : TextBox { public static readonly DependencyProperty CaretPositionProperty = DependencyProperty.Register("CaretPosition", typeof(int), typeof(MyTextBox), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnCaretPositionChanged)); public int CaretPosition { get { return (int)GetValue(CaretPositionProperty); } set { SetValue(CaretPositionProperty, value); } } public MyTextBox() { SelectionChanged += (s, e) => CaretPosition = CaretIndex; } private static void OnCaretPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as MyTextBox).CaretIndex = (int)e.NewValue; } } } 

… y en mi XAML:

 xmlns:controls="clr-namespace:IU.Controls" ...  

… y propiedad CaretPosition en el modelo de vista, por supuesto. Si no va a vincular su View Model con otros controles de edición de texto, esto puede ser suficiente, si es así, probablemente necesitará otra solución.