Note that there are some explanatory texts on larger screens.

plurals
  1. POI am not being notified when CaretIndex is Changed in MVVM
    primarykey
    data
    text
    <p>I know that CaretIndex is not a Dependency Property.</p> <p>So I registered it as follows:</p> <pre><code> public class TextBoxHelper : TextBox { public static readonly DependencyProperty CaretIndexProperty = DependencyProperty.Register ( "CaretIndex", typeof(int), typeof(TextBoxHelper), new FrameworkPropertyMetadata ( 0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, CaretIndexChanged ) ); public static int GetCaretIndex(DependencyObject obj) { return (int)obj.GetValue(CaretIndexProperty); } public static void SetCaretIndex(DependencyObject obj, int value) { obj.SetValue(CaretIndexProperty, value); } //public new int CaretIndex //{ // get { return (int)GetValue(CaretIndexProperty); } // set { SetValue(CaretIndexProperty, value); } //} protected override void OnTextChanged(TextChangedEventArgs e) { base.OnTextChanged(e); CaretIndex = base.CaretIndex; } protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); CaretIndex = base.CaretIndex; } protected override void OnKeyUp(KeyEventArgs e) { base.OnKeyUp(e); CaretIndex = base.CaretIndex; } protected override void OnMouseDown(MouseButtonEventArgs e) { base.OnMouseDown(e); CaretIndex = base.CaretIndex; } protected override void OnMouseUp(MouseButtonEventArgs e) { base.OnMouseUp(e); CaretIndex = base.CaretIndex; } private static void CaretIndexChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { if (obj is TextBox) { ((TextBox)obj).CaretIndex = (int)e.NewValue; } } } </code></pre> <p>Then I created a property named CaretIndex in my ViewModel. It implements the INotifyPropertyChanged interface.</p> <pre><code>private int _caretIndex; public int CaretIndex { get { return _caretIndex; } set { _caretIndex = value; OnPropertyChanged("CaretIndex"); } } </code></pre> <p>Then I created bindings in my ComboBox as follows:</p> <pre><code>&lt;ComboBox x:Name="cbUnder" ItemsSource="{Binding GroupsAndCorrespondingEffects}" IsEditable="True" SelectedItem="{Binding SelectedGroup, Mode=TwoWay}" Text="{Binding InputValue, UpdateSourceTrigger=PropertyChanged}" TextSearch.TextPath="GroupName" Grid.Column="1" Grid.ColumnSpan="4" Grid.Row="3" vm:TextBoxHelper.CaretIndex="{Binding CaretIndex, UpdateSourceTrigger=PropertyChanged}"&gt; &lt;ComboBox.Resources&gt; &lt;DataTemplate DataType="{x:Type vm:GroupAndCorrespondingEffect}"&gt; &lt;StackPanel Orientation="Horizontal"&gt; &lt;TextBlock Text="{Binding GroupName}" Width="250"&gt; &lt;TextBlock.Style&gt; &lt;Style TargetType="TextBlock"&gt; &lt;Style.Triggers&gt; &lt;DataTrigger Binding="{Binding IsHighlighted}" Value="True"&gt; &lt;Setter Property="Foreground" Value="Blue" /&gt; &lt;Setter Property="FontWeight" Value="Bold"/&gt; &lt;/DataTrigger&gt; &lt;/Style.Triggers&gt; &lt;/Style&gt; &lt;/TextBlock.Style&gt; &lt;/TextBlock&gt; &lt;TextBlock Text="{Binding CorrespondingEffect}" /&gt; &lt;/StackPanel&gt; &lt;/DataTemplate&gt; &lt;/ComboBox.Resources&gt; &lt;/ComboBox&gt; </code></pre> <p>Still I am not being notified when CaretIndex is Changed.</p> <p>From the code above I have got <code>IsEditable = True</code> and <code>IsTextSearchEnabled = True</code>.</p> <p>But when I type any character in combobox it appends the name of the whole item in the textbox of combobox.</p> <p>I actually want to have a combobox to highlight all the items that matches what I typed but due to the text appending I can get only one item highlighted.</p> <p>So, I need the text that I have typed. i.e. The text that is not selected. (Because the text that is appended is also selected).</p> <p>So, If I get the caretIndex then I can use the substring method on the text to get what I typed. According to that it will highlight the text.</p> <p><strong>Update</strong></p> <pre><code>&lt;Style TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}"&gt; &lt;Setter Property="Template"&gt; &lt;Setter.Value&gt; &lt;ControlTemplate TargetType="ComboBox"&gt; &lt;TextBox x:Name="PART_EditableTextBox" CaretIndex="vm:TextBoxHelper.CaretIndex" /&gt; &lt;/ControlTemplate&gt; &lt;/Setter.Value&gt; &lt;/Setter&gt; &lt;/Style&gt; </code></pre> <p>I have tried the above code but it says me input string was not in a correct format.</p> <p>So, I have replaced the above code with :</p> <pre><code>&lt;Style TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}"&gt; &lt;Setter Property="Template"&gt; &lt;Setter.Value&gt; &lt;ControlTemplate TargetType="ComboBox"&gt; &lt;TextBox x:Name="PART_EditableTextBox" vm:TextBoxHelper.CaretIndex="{Binding CaretIndex, UpdateSourceTrigger=PropertyChanged}" /&gt; &lt;/ControlTemplate&gt; &lt;/Setter.Value&gt; &lt;/Setter&gt; &lt;/Style&gt; </code></pre> <p>Now I do not get any error but my combobox looks like a textbox. I mean it has lost its dropdown part. And I have checked by using breakpoints in my viewmodel. But still I am not getting notified when caretIndex changes.</p> <p><strong>Update2</strong></p> <pre><code>&lt;TextBox x:Name="PART_EditableTextBox" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource TemplatedParent}}" Margin="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"&gt; &lt;TextBox.Style&gt; &lt;Style TargetType="{x:Type TextBox}"&gt; &lt;Setter Property="vm:TextBoxHelper.CaretIndex" Value="{Binding CaretIndex, UpdateSourceTrigger=PropertyChanged}" /&gt; . . . </code></pre> <p>The above code does not work, So I updated it like below :</p> <pre><code>&lt;vm:TextBoxHelper x:Name="PART_EditableTextBox" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource TemplatedParent}}" Margin="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"&gt; &lt;vm:TextBoxHelper.Style&gt; &lt;Style TargetType="{x:Type vm:TextBoxHelper}"&gt; &lt;Setter Property="vm:TextBoxHelper.CaretIndex" Value="{Binding CaretIndex, UpdateSourceTrigger=PropertyChanged}" /&gt; . . . </code></pre> <p>Still it does not work.</p> <p><strong>Update 3</strong></p> <p>Here is my <code>App.xaml</code> file</p> <pre><code>&lt;Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:comboFDD="clr-namespace:ERP_Lite_Trial.Views.DesignRelatedCode" x:Class="ERP_Lite_Trial.App" StartupUri="Views/MainWindow.xaml"&gt; &lt;Application.Resources&gt; &lt;ResourceDictionary&gt; &lt;ResourceDictionary.MergedDictionaries&gt; &lt;ResourceDictionary Source="Views/Pages/ResourceDictionary1.xaml"/&gt; &lt;/ResourceDictionary.MergedDictionaries&gt; &lt;Style TargetType="{x:Type ComboBox}"&gt; &lt;Setter Property="comboFDD:ComboBox_ForceDropDown.OpenDropDownAutomatically" Value="True"/&gt; &lt;/Style&gt; &lt;/ResourceDictionary&gt; &lt;/Application.Resources&gt; &lt;/Application&gt; </code></pre> <p><strong>Update 4</strong></p> <p>I have also got a property InputValue in my ViewModel</p> <pre><code>private string _inputValue; public string InputValue { get { return _inputValue; } set { _inputValue = value; OnPropertyChanged("GroupsAndCorrespondingEffects"); for (int i = 0; i &lt; GroupsAndCorrespondingEffects.Count; i++) { string WordToSearch = _inputValue; if (_caretIndex != 0 || _caretIndex != null) { WordToSearch = _inputValue.Substring(0, _caretIndex); } GroupsAndCorrespondingEffects[i].IsHighlighted = GroupsAndCorrespondingEffects[i].GroupName.StartsWith(WordToSearch); } } } </code></pre> <p>Another property I have got is IsHilighted. This property is defined in GroupsAndCorrespondingEffects Class. Using this class I get my data from database.</p> <p>Code for GroupsAndCorrespondingEffects.cs</p> <pre><code>public class GroupAndCorrespondingEffect : INotifyPropertyChanged { private string _groupName; public string GroupName { get { return _groupName; } set { _groupName = value; OnPropertyChanged("GroupName"); } } private string _correspondingEffect; public string CorrespondingEffect { get { return _correspondingEffect; } set { _correspondingEffect = value; OnPropertyChanged("CorrespondingEffect"); } } private bool _isHighlighted; public bool IsHighlighted { get { return _isHighlighted; } set { _isHighlighted = value; OnPropertyChanged("IsHighlighted"); } } public void OnPropertyChanged([CallerMemberName] string propertyName = null) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; } </code></pre> <p>Propcess of invoking properties in ViewModel is as follows:</p> <p>Now when I type 1st Character in combobox :</p> <pre><code>CaretIndex = 0 CaretIndex = 0 InputValue = Text of combobox CaretIndex = 1 CaretIndex = 1 </code></pre> <p>When I type 2nd Character in combobox :</p> <pre><code>CaretIndex = 1 InputValue = Text of combobox CaretIndex = 2 </code></pre> <p>When I type 3rd Character in combobox :</p> <pre><code>CaretIndex = 2 InputValue = Text of combobox CaretIndex = 3 </code></pre> <p>And so on....</p> <p>My logic for Highlighting Items in combobox is based on change in CaretIndex. This logic is written in the set part of <code>InputValue</code> property. But due to the fact mentioned above that InputValue is invoked before the CaretIndex takes new value I get incorrect HighLights.</p> <p><strong>Update 5 - For Retain Selection Lost</strong></p> <p>I have added SelectionStart and SelectionLength properties in our TextBoxHelper Class as they are not dependency properties.</p> <p>Here is the code:</p> <pre><code> public static readonly DependencyProperty BindableSelectionStartProperty = DependencyProperty.RegisterAttached ( "BindableSelectionStart", typeof(int), typeof(TextBoxHelper), new PropertyMetadata ( BindableSelectionStartChanged ) ); public static readonly DependencyProperty BindableSelectionLengthProperty = DependencyProperty.RegisterAttached ( "BindableSelectionLength", typeof(int), typeof(TextBoxHelper), new PropertyMetadata ( BindableSelectionLengthChanged ) ); public static int GetBindableSelectionStart(DependencyObject obj) { return (int)obj.GetValue(BindableSelectionStartProperty); } public static void SetBindableSelectionStart(DependencyObject obj, int value) { obj.SetValue(BindableSelectionStartProperty, value); } public int BindableSelectionStart { get { return (int)this.GetValue(BindableSelectionStartProperty); } set { this.SetValue(BindableSelectionStartProperty, value); } } public static int GetBindableSelectionLength(DependencyObject obj) { return (int)obj.GetValue(BindableSelectionLengthProperty); } public static void SetBindableSelectionLength(DependencyObject obj, int value) { obj.SetValue(BindableSelectionLengthProperty, value); } public int BindableSelectionLength { get { return (int)this.GetValue(BindableSelectionLengthProperty); } set { this.SetValue(BindableSelectionLengthProperty, value); } } private static void BindableSelectionStartChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is TextBox) { ((TextBox)d).SelectionStart = (int)e.NewValue; } } private static void BindableSelectionLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is TextBox) { ((TextBox)d).SelectionLength = (int)e.NewValue; } } protected override void OnSelectionChanged(RoutedEventArgs e) { base.OnSelectionChanged(e); BindableSelectionStart = base.SelectionStart; BindableSelectionLength = base.SelectionLength; } </code></pre> <p>Then I have created the corresponding properties in my ViewModel.</p> <pre><code> private int _selectionStart; public int SelectionStart { get { return _selectionStart; } set { _selectionStart = value; OnPropertyChanged("SelectionStart"); } } private int _selectionLength; public int SelectionLength { get { return _selectionLength; } set { _selectionLength = value; OnPropertyChanged("SelectionLength"); } } </code></pre> <p>After that I have changed <code>CaretIndex</code> and <code>InputValue</code> properties of ViewModel as follows:</p> <pre><code> private int _caretIndex; public int CaretIndex { get { return _caretIndex; } set { _caretIndex = value; OnPropertyChanged("CaretIndex"); if (InputValue != null &amp;&amp; CaretIndex &gt;= 0) { SelectionStart = CaretIndex; Debug.WriteLine(string.Format("Selection Start : {0}", SelectionStart)); SelectionLength = InputValue.Length - CaretIndex; Debug.WriteLine(string.Format("Selection Length : {0}", SelectionLength)); } for (int i = 0; i &lt; GroupsAndCorrespondingEffects.Count; i++) { string WordToSearch = InputValue; if (_caretIndex != 0 &amp;&amp; _caretIndex &gt; 0) { WordToSearch = InputValue.Substring(0, _caretIndex); } if (WordToSearch != null) { GroupsAndCorrespondingEffects[i].IsHighlighted = GroupsAndCorrespondingEffects[i].GroupName.StartsWith(WordToSearch); } } } } private string _inputValue; public string InputValue { get { return _inputValue; } set { _inputValue = value; OnPropertyChanged("GroupsAndCorrespondingEffects"); if (InputValue != null &amp;&amp; CaretIndex &gt;= 0) { SelectionStart = CaretIndex; Debug.WriteLine(string.Format("Selection Start : {0}", SelectionStart)); SelectionLength = InputValue.Length - CaretIndex; Debug.WriteLine(string.Format("Selection Length : {0}", SelectionLength)); } for (int i = 0; i &lt; GroupsAndCorrespondingEffects.Count; i++) { string WordToSearch = _inputValue; if (_caretIndex != 0 &amp;&amp; _caretIndex &gt; 0 &amp;&amp; _caretIndex &lt; _inputValue.Length) { WordToSearch = _inputValue.Substring(0, _caretIndex); } GroupsAndCorrespondingEffects[i].IsHighlighted = GroupsAndCorrespondingEffects[i].GroupName.StartsWith(WordToSearch); } } } </code></pre> <p>The last change I made was in ResourceDictionary as Follows:</p> <pre><code>&lt;vm:TextBoxHelper x:Name="PART_EditableTextBox" MyCaretIndex="{Binding CaretIndex}" BindableSelectionStart="{Binding SelectionStart}" BindableSelectionLength="{Binding SelectionLength}" ........... </code></pre> <p>In output window I can see the SelectionStart as well as SelectionLength changed but can't see any visual change in the combobox.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload