Jayson Ragasa
Jayson Ragasa

Reputation: 1029

ComboBox Up/Down arrow keys issue after Items is repopulated

I am creating a custom ComboBox control with Google Search results implementation but I am running into some problem using the arrow keys.

Details of the problem
Please watch this video as I demonstrate the problem with UP and DOWN arrow keys and take a look on the output panel as well.

http://screencast.com/t/DFkmlDKR

In the video, I tried searching for "a" (just a test) and returns the Google search results that starts with "a" then I am pressing the DOWN and UP arrow keys. In the output panel, it shows the highlighted item as I press these keys.
enter image description here

Then I typed the next letter "l". Now If you noticed on the output panel, the selection is now "null" but I'm still pressing the UP & DOWN arrow keys.
enter image description here

And when you hover on the item again using the mouse pointer, it will start working again.
enter image description here

I am stuck with this problem for days and haven't figured out the solution.

I have uploaded the test version of this control so you can play with it as well. Here it is GoogleSuggestionComboBox
enter image description here

My goal here is to make the UP & DOWN arrow keys work all the time.

In this section of the code enter image description here I tried adding

SelectedIndex = 0;

after the ForEach statement so everytime the collection is repopulated with the new results, it will select the first result. Unfortunately, it did not work.

You can download the test code so you can play and test the problem. http://sdrv.ms/1eWV3Bc and here's the code for the ComboBox as well.

using GoogleSuggestionComboBox.Model;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace GoogleSuggestionComboBox
{
    public class ComboBoxExC : ComboBox
    {
        GoogleSuggest google;
        TextBox textbox;
        string _text = string.Empty;
        string _last_text = string.Empty;

        public ComboBoxExC()
        {
            if (DesignerProperties.GetIsInDesignMode(this))
            {

            }
            else
            {
                this.Loaded += ComboBoxExC_Loaded;

                google = new GoogleSuggest();
                google.OnGoogleSuggestAvailable += google_OnGoogleSuggestAvailable;

                // since we have OnSelectionChanged "disabled"
                // we need a way to know if the item in ComboBox is selected using mouse
                EventManager.RegisterClassHandler(typeof(ComboBoxItem), ComboBoxItem.MouseDownEvent, new MouseButtonEventHandler(OnItemMouseDown));
            }
        }

        void ComboBoxExC_Loaded(object sender, RoutedEventArgs e)
        {
            this.textbox = (TextBox)Template.FindName("PART_EditableTextBox", this);
        }

        private void OnItemMouseDown(object sender, MouseButtonEventArgs e)
        {
            var comboBoxItem = sender as ComboBoxItem;
            if (comboBoxItem != null && comboBoxItem.IsHighlighted)
            {
                Model_SuggestedQueries m = (Model_SuggestedQueries)comboBoxItem.Content;
                Go(m.Query);
            }
        }

        protected override void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            // don't do anything so the .Text value won't change.

            //base.OnSelectionChanged(e);
        }

        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            this.IsDropDownOpen = true;

            base.OnPreviewKeyDown(e);

            d("key: " + e.Key.ToString());

            if (this.SelectedItem != null)
            {
                Model_SuggestedQueries m = (Model_SuggestedQueries)this.SelectedItem;
                d("selected: " + m.Query);
            }
            else
            {
                d("null");
            }
        }

        protected override void OnPreviewKeyUp(KeyEventArgs e)
        {
            base.OnPreviewKeyUp(e);

            if (e.Key == Key.Enter)
            {
                if (this.SelectedItem == null)
                {
                    Go(this.Text);

                }
                else
                {
                    Model_SuggestedQueries m = (Model_SuggestedQueries)this.SelectedItem;
                    Go(m.Query);
                }
            }
            else
            {
                if (this.Text != this._last_text)
                {
                    google.LookForSuggestion(this.Text);

                    this._last_text = this.Text;
                }
            }
        }

        void google_OnGoogleSuggestAvailable(object sender, List<Model.Model_SuggestedQueries> suggestions)
        {
            this.Items.Clear();

            suggestions.ForEach((a) =>
            {
                this.Items.Add(a);
            });
        }

        void d(object a)
        {
            Debug.WriteLine(">>> " + a);
        }

        void Go(string query)
        {
            Process.Start("https://www.google.com.ph/search?q=" + query);

            // clear suggestions
            this.Items.Clear();
        }
    }
}

MainWindow.xaml

<Window x:Class="GoogleSuggestionComboBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:GoogleSuggestionComboBox"
        Title="MainWindow" Height="133" Width="261" WindowStartupLocation="CenterScreen"
        >
    <Grid>
        <StackPanel Margin="10">
            <TextBlock Text="Search" />
            <l:ComboBoxExC 
                IsEditable="True" 
                IsTextSearchEnabled="False"
                TextSearch.TextPath="Query"
                >
                <l:ComboBoxExC.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Query}" />
                    </DataTemplate>
                </l:ComboBoxExC.ItemTemplate>
            </l:ComboBoxExC>
        </StackPanel>
    </Grid>
</Window>

Thank you,
Jayson

Upvotes: 3

Views: 2835

Answers (2)

EpicKip
EpicKip

Reputation: 4043

This is a pretty old question but I ran into about the same problem. The main issue for me was after selecting an item or clearing selection (setting it to -1) I could not go through the items with the arrow keys anymore until I hovered over them with my mouse.

After some days of struggling I found a fix for this:

KeyboardNavigation.SetDirectionalNavigation( this, KeyboardNavigationMode.Cycle );

this is the combobox, and this line is in the constructor of a sub classed combobox.

Upvotes: 4

Greg Gum
Greg Gum

Reputation: 38049

I don't know the exact issue, but here is a suggestion:

Don't subclass the ComboBox - you don't need to.

Just drop one on the MainForm, and then work with it from the code behind - it is much easier to work with it like that. You only need to subclass if you need to change the way a combo-box works which is not typical.

I tried downloading the test project, but it is not a zip file - it is a .7z which I could not open.

Also, you main form is a Window. That may not be an issue, but try creating a new project and just working with the Main form the project gives you. There is some wiring up that is done in the App that calls the MainForm that will catch exceptions etc, and that may give you more data as to what the issue is.

Greg

Upvotes: -1

Related Questions