2015-01-30 2 views
3

Привет Я пытаюсь привязать к свойству TextBox.CaretIndex, который не является DependencyProperty, поэтому я создал Behavior, но он не работает должным образом.Как привязать к CaretIndex aka позицию курсора текстового поля

Expectation (при фокусировке)

  • по умолчанию = 0
  • если изменить значение в моей зрения он должен изменить значение в моей ViewModel
  • если я изменить значение в моем viewmodel он должен изменить значение в моем вид

Текущее поведение

  • значение ViewModel вызывается из них, когда окно открывается

Code-за

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

<TextBox Text="{Binding TextTemplate,UpdateSourceTrigger=PropertyChanged}" 
     local:TextBoxBehavior.CursorPosition="{Binding CursorPosition}"/> 

Дополнительная информация

Я думаю, что есть что-то на самом деле здесь не так, потому что мне нужно, чтобы вывести его из DependencyObject, которая никогда не была нужна раньше, потому что CursorPositionProperty уже DependencyProperty, так что это должно быть достаточно. Я также думаю, что мне нужно использовать некоторые события в моем Behavior, чтобы правильно установить мой CursorPositionProperty, но я не знаю, какой.

ответ

5

После борьбы с моим поведением, я могу представить вам 99% рабочего раствора

Поведение

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

<TextBox Height="50" VerticalAlignment="Top" 
      Name="TestTextBox" 
      Text="{Binding MyText}" 
      vm:TextBoxCursorPositionBehavior.TrackCaretIndex="True" 
      vm:TextBoxCursorPositionBehavior.CursorPosition="{Binding CursorPosition,Mode=TwoWay}"/> 

    <TextBlock Height="50" Text="{Binding CursorPosition}"/> 

есть только на вещи я не знаю, почему это не работает =>BindsTwoWayByDefault = true. это не влияет на привязку, насколько я могу вам рассказать. Мне нужно установить режим привязки в явном виде в XAML

+1

** public static int GetTrackCaretIndex (DependencyObject dependencyObject) ** должен возвращать ** bool ** как это логическое свойство. + ** return (bool) dependencyObject.GetValue (TrackCaretIndexProperty); ** В противном случае вы получите _ «Строка ввода не была в правильном формате». _ Ошибка XAML. – Jedzia

+0

@Jedzia nice catch – WiiMaxx

+0

CursorPosition также необходимо использовать RegisterAttached – user3391859

1

Как вы говорили, TextBox.CaretIndex Propertyэто неDependencyProperty, так что вы не можете связать данные с ним. Даже с вашим собственным DependencyProperty, он не сработает ... как вы ожидаете получить уведомление, когда TextBox.CaretIndex Изменения свойств?

+0

Я думал, что могу использовать некоторые события, чтобы изменить значение – WiiMaxx

+0

Конечно, вы можете изменить значение, но вы не будете уведомлены, когда он изменится сам по себе. Однако вам не нужно 'DependencyProperty' просто изменить значение. – Sheridan

+0

Хорошо, я вижу, так как бы вы попытались получить «TextBox.CaretIndex»? – WiiMaxx

0

У меня возникла аналогичная проблема, и самым простым решением для меня было унаследовать от TextBox и добавить a DependencyProperty.Так это выглядит следующим образом:

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; 
     } 
    } 
} 

... и в моем XAML:

xmlns:controls="clr-namespace:IU.Controls" 
... 
<controls:MyTextBox CaretPosition="{Binding CaretPosition}"/> 

... и CaretPosition недвижимость в виде модели, конечно. Если вы не собираетесь привязывать свою модель View к другим элементам редактирования текста, этого может быть достаточно, если да - вам, вероятно, понадобится другое решение.

Смежные вопросы