This is a migrated thread and some comments may be shown as answers.

AutoCompleteBox loses highlighting when the item collection changes while the AutoCompleteBox is active and the popup is open.

6 Answers 143 Views
AutoCompleteBox
This is a migrated thread and some comments may be shown as answers.
Pooja
Top achievements
Rank 1
Pooja asked on 14 Oct 2014, 09:17 PM
AutoCompleteBox loses its highlighting when the itemsource collection changes. To reproduce this issue type in the AutoCompleteBox and while it’s active and the popup is open, trigger a collection change event. The highlighting will automatically disappear, now if the collection changes again the highlighting reappears. This keeps toggling back and forth.

Attached is the screenshot.
Below are the code snippets.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using Telerik.Windows.Controls;
 
namespace HighlightMatchingItemsText
{
    public class Country
    {
        public string Name { get; set; }
        public string Capital { get; set; }
    }
 
    public class ViewModel : ViewModelBase
    {
        private ObservableCollection<Country> countries;
 
        public ViewModel()
        {
            this.Countries = new ObservableCollection<Country>()
            {
                new Country() { Name = "Australia", Capital = "Canberra" },
                new Country() { Name = "Bulgaria", Capital = "Sofia" },
                new Country() { Name = "Canada", Capital = "Ottawa" },
                new Country() { Name = "Denmark", Capital = "Copenhagen" },
                new Country() { Name = "France", Capital = "Paris" },
                new Country() { Name = "Germany", Capital = "Berlin" },
                new Country() { Name = "India", Capital = "New Delhi" },
                new Country() { Name = "Italy", Capital = "Rome" },
                new Country() { Name = "Norway", Capital = "Oslo" },
                new Country() { Name = "Russia", Capital = "Moscow" },
                new Country() { Name = "Spain", Capital = "Madrid" },
                new Country() { Name = "United Kingdom", Capital = "London" },
                new Country() { Name = "United States", Capital = "Washington, D.C." },
            };
 
            var o = System.Reactive.Linq.Observable.Start(() =>
            {
                //starts on a background thread.
                while (true)
                {
                    Thread.Sleep(6000);
                    this.Countries = new ObservableCollection<Country>()
                    {
                        new Country() { Name = "Australia", Capital = "Canberra" },
                        new Country() { Name = "Bulgaria", Capital = "Sofia" },
                        new Country() { Name = "Canada", Capital = "Ottawa" },
                        new Country() { Name = "Denmark", Capital = "Copenhagen" },
                    };
                    Console.WriteLine("Collection Changed");
                }
            });
 
        }
 
         public ObservableCollection<Country> Countries
        {
            get { return this.countries; }
            set
            {
                if (this.countries != value)
                {
                    this.countries = value;
                    this.OnPropertyChanged(() => this.Countries);
                }
            }
        }
    }
}

<UserControl x:Class="HighlightMatchingItemsText.Example"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
             xmlns:local="clr-namespace:HighlightMatchingItemsText"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300" Width="300">
    <UserControl.DataContext>
        <local:ViewModel />
    </UserControl.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Text="Type A in the autocomplete box, Australia gets highlighted. Keep the drop down open and wait for 6 seconds, the collection changes and the highlighting dissappears.
                   Wait for another 6 seconds, the collection changes and the highlighting reappaers. This keeps toggling. "
                   TextWrapping="Wrap"
                   FontWeight="Bold"
                   Margin="20"/>
        <telerik:RadAutoCompleteBox x:Name="AutoComplete"
                                    Grid.Row="1"
                                    Margin="20"
                                    ItemsSource="{Binding Countries}"
                                    TextSearchPath="Name"
                                    TextSearchMode="Contains"
                                    AutoCompleteMode="Suggest"
                                    >
        </telerik:RadAutoCompleteBox>       
    </Grid>
</UserControl>







6 Answers, 1 is accepted

Sort by
0
Pooja
Top achievements
Rank 1
answered on 15 Oct 2014, 10:09 PM
The InvalidateHighlightedIndex method in the AutoCompleteHelper.cs file sets the HighlightedIndexInternal to -1 if the previous highlighted item is not null and object does not match the current items. This causes the highlighting to disappear when source changes and the previous HighlightedItem is not null. When source changes again, since this time the HighlightedItem is null, HighlightedIndexInternal is not set to -1 but to highlightedIndex, which causes the toggling behaviour. Why do we have this following condition? Can we simply set HighlightedIndexInternal to the value calculated by the FindHighlightedIndex method if its within the range, else to -1?
if (this.AutoCompleteMode.HighlightedItem != null && !filteredItems.Any(x => x == this.AutoCompleteMode.HighlightedItem))
           {
               this.AutoCompleteMode.HighlightedIndexInternal = -1;
           }

private void InvalidateHighlightedIndex(IEnumerable<object> filteredItems)
        {
            int highlightedIndex = 0;
            if (filteredItems.Count() != 1)
            {
                highlightedIndex = filteredItems.Count() <= this.AutoCompleteMode.HighlightedIndexInternal ? -1 : this.AutoCompleteMode.HighlightedIndexInternal;
            }
 
            if (this.AutoCompleteMode.HighlightedItem != null && !filteredItems.Any(x => x == this.AutoCompleteMode.HighlightedItem))
            {
                this.AutoCompleteMode.HighlightedIndexInternal = -1;
            }
            else
            {
                this.AutoCompleteMode.HighlightedIndexInternal = highlightedIndex;
            }
 
            if (highlightedIndex == -1)
            {
                this.HighlightItem(-1);
            }
        }

0
Vladi
Telerik team
answered on 17 Oct 2014, 10:12 AM
Hello Pooja,

Thank you for contacting us.

All of your remarks are correct. Indeed the internal property (HighlightedIndexInternal) is being refreshed when the ItemsSource is changed while the DropDown is opened and there is already a HighlightedItem. This is caused by the condition which is checking if that item is present in the FilteredItems collection. As a general rule when using an ItemsControl control with ItemsSource collection of custom business objects it is important to override that type's Equals method. Because of the nature of the RadAutoCompleteBox control the objects from it's ItemsSource are being compared to each other and in scenarios where those are custom objects the default Equals implementation is not always correct. One such scenario is the described one in the post. When the ItemsSource is changed with a new instance of a collection that contains an object which properties contain the same value the Equals method return false which is expected from the framework's point of view. For example:
  • When an Country object with  Name = "Australia", Capital = "Canberra" is being compared to a new instance of a Country with the same properties.
  • The default Equal method will return false when those two objects are compared via the .Equals(..) method.

The business layer may treat those as the same object but the .NET framework does not as they are different references in the memory. This is resolved by a custom Equals implementation in the business object.

We have found that even if the above is implemented is implemented there is a bug in the RadAutoCompleteBox control and we will do our best to fix the issue as soon as possible. I updated your Telerik point for bringing this to our attention.


Regards,
Vladi
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
0
Pooja
Top achievements
Rank 1
answered on 17 Oct 2014, 01:40 PM
Thank you Vladi. I agree we need to support the custom Equal's method. But since we do not raise HighlightedIndexChanged event, when the index remains the same, it will still not resolve the issue. I changed the InvalidateHighlightedIndex as follows which did resolve the highlighting issue, but not sure if this is the right approach.

private void InvalidateHighlightedIndex(IEnumerable<object> filteredItems)
      {
          int highlightedIndex = 0;
          if (filteredItems.Count() != 1)
          {
              highlightedIndex = filteredItems.Count() <= this.AutoCompleteMode.HighlightedIndexInternal ? -1 : this.AutoCompleteMode.HighlightedIndexInternal;
          }
 
          this.AutoCompleteMode.HighlightedIndexInternal = highlightedIndex;
 
          if (this.AutoCompleteMode.HighlightedItem != null && !filteredItems.Any(x => x == this.AutoCompleteMode.HighlightedItem))
          {
              this.HighlightItem(highlightedIndex);
          }
 
          if (highlightedIndex == -1)
          {
              this.HighlightItem(-1);
          }
      }
0
Vladi
Telerik team
answered on 17 Oct 2014, 02:53 PM
Hi Pooja,

We are already working on a fix for this issue. When the fix is released all that would be required to resolve it in your project would be to override the Equals method of your business object.

For your convenience I logged the discussed issue in our feedback portal where you can track its status. The feedback item can be found here.

Regards,
Vladi
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
0
Pooja
Top achievements
Rank 1
answered on 17 Oct 2014, 05:56 PM
Thanks Vladi. I also noticed the highlighting disappears when you use backspace. Image attached.

0
Vladi
Telerik team
answered on 20 Oct 2014, 08:03 AM
Hello,

By design when the backspace keyboard key is pressed while the DropDown is opened any previously highlighted item is removed. This is done because in the concept of the RadAutoCompleteBox control the backspace keyboard key is used to delete the input and there should not be any highlighted item after it is pressed.

Customizing this behavior could be achieved by creating a custom HighlightBehavior. More information about this feature can be found in our online documentation here.

Regards,
Vladi
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
Tags
AutoCompleteBox
Asked by
Pooja
Top achievements
Rank 1
Answers by
Pooja
Top achievements
Rank 1
Vladi
Telerik team
Share this question
or