DropDownList AutoComplete and exact match problem

6 posts, 0 answers
  1. Ralf
    Ralf avatar
    77 posts
    Member since:
    Jun 2012

    Posted 22 Jan 2014 Link to this post

    Hello,

    when I enter a value and it matches only one entry in the autocomplete dropdown list the dropdownbox will be closed, but the SelecedIndexChanged event of the DropDownList control will not fired.
    Only when I select a entry in the dropdown box the event will be fired.

    For example I enter "Germany", one item matches and the dropdownbox closing. The SelectedIndexChanged event will not fired. It will be fired after leaving the control by tab key or click another control like a button.
    When I enter "Germ" two items matches. When I select one the dropdown closing and the SelectedIndexChanged event will be fired.

    Why the SelectedIndexChanged event will not fired? It have to fire or not? How to solve?

    Here is my code:
    public partial class EulaViewerView : UserControl
    {
        #region private Members
     
        /// <summary>
        /// The BackgroundWorker that is used to load the country list asynchronous.
        /// </summary>
        private BackgroundWorker _asyncWorker;
     
        #endregion
     
        #region Constructor
     
        /// <summary>
        /// The constructor of the class.
        /// </summary>
        public EulaViewerView()
        {
            InitializeComponent();
            this.Localize();
            CountrySelector.DropDownListElement.AutoCompleteSuggest.DropDownList.VisualItemFormatting += DropDownList_VisualItemFormatting;
            this.InitializeControl();
        }
     
        #endregion
     
        #region BackgroundWorker methods
     
        /// <summary>
        /// BackgroundWorker finished event handling.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void asyncWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.Cursor = Cursors.Hand;
        }
     
        /// <summary>
        /// Adding in background created DropDownList items to the DropDonwList.
        /// </summary>
        /// <param name="sender">The instance of the BackgroundWorker.</param>
        /// <param name="e">The BackgroundWorker event arguments.</param>
        private void asyncWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.UserState is RadListDataItem)
                this.CountrySelector.Items.Add(e.UserState as RadListDataItem);
        }
     
        /// <summary>
        /// Loads the country list and create DropDownList items
        /// </summary>
        /// <param name="sender">The instance of the BackgroundWorker.</param>
        /// <param name="e">The BackgroundWorker event arguments.</param>
        private void asyncWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            CountryList countyList = new CountryList();
            BackgroundWorker worker = sender as BackgroundWorker;
     
            foreach (Country country in countyList.Countries)
            {
                if (country.CountryName != "")
                {
                    string imagekey = this.GetImageKey(country);
                    if (!string.IsNullOrEmpty(imagekey))
                    {
                        RadListDataItem item = new RadListDataItem(country.CountryName);
                        item.Image = this.imageList1.Images[this.GetImageKey(country)];
                        item.Value = country;
                        item.ForeColor = Color.Black;
                        if (EulaInfo.Instance.CountrySelected && country.CountryName == EulaInfo.Instance.SelectedCountry.CountryName)
                            item.Selected = true;
                        worker.ReportProgress(1, item);
                    }
                }
            }
        }
     
        #endregion
     
        #region helper methods
     
        /// <summary>
        /// Formatting event handling for DropDownListItems to add country flag in autocomplete list.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The arguments.</param>
        private void DropDownList_VisualItemFormatting(object sender, VisualItemFormattingEventArgs args)
        {
            args.VisualItem.Image = this.imageList1.Images[this.GetImageKey((Country)args.VisualItem.Data.Value)];
        }
     
        /// <summary>
        /// Inits the control components and starts loading the countries in background.
        /// </summary>
        private void InitializeControl()
        {
            this.Cursor = Cursors.WaitCursor;
            this.CountrySelector.DropDownListElement.AutoCompleteSuggest.SuggestMode = SuggestMode.Contains;
            this.CountrySelector.DropDownListElement.TextBox.StretchVertically = true;
            _asyncWorker = new BackgroundWorker();
            _asyncWorker.DoWork += asyncWorker_DoWork;
            _asyncWorker.ProgressChanged += asyncWorker_ProgressChanged;
            _asyncWorker.RunWorkerCompleted += asyncWorker_RunWorkerCompleted;
            _asyncWorker.WorkerReportsProgress = true;
            _asyncWorker.RunWorkerAsync();
        }
     
        /// <summary>
        /// Gets the image key for the given country in imageList1.
        /// </summary>
        /// <param name="country"></param>
        /// <returns></returns>
        private string GetImageKey(Country country)
        {
            string retval = string.Empty;
     
            if (!string.IsNullOrEmpty(country.EnglishName))
                retval = "flag_" + country.EnglishName + ".png";
     
            return retval;
        }
     
        #endregion
     
        #region Control event handling methods
     
        /// <summary>
        /// Syncronize relevant control states to EulaInfo instance.
        /// </summary>
        /// <param name="sender">The control instance.</param>
        /// <param name="e">The event arguments.</param>
        private void AgreeEulaActor_CheckedChanged(object sender, EventArgs e)
        {
            EulaInfo.Instance.Accepted = this.AgreeEulaActor.Checked;
        }
     
        /// <summary>
        /// Syncronize relevant control states to EulaInfo instance.
        /// </summary>
        /// <param name="sender">The control instance.</param>
        /// <param name="e">The event arguments.</param>
        private void DisagreeEulaActor_CheckedChanged(object sender, EventArgs e)
        {
            EulaInfo.Instance.Accepted = this.AgreeEulaActor.Checked;
        }
     
        /// <summary>
        /// Print out the actually shown eula.
        /// </summary>
        /// <param name="sender">The control instance.</param>
        /// <param name="e">The event arguments.</param>
        private void btnPrintActor_Click(object sender, EventArgs e)
        {
            this.EulaReader.Print();
        }
     
        /// <summary>
        /// Change DropDownList style and loads the embedded eula document for the selected country into the PDF reader control.
        /// </summary>
        /// <param name="sender">The DropDownList instance.</param>
        /// <param name="e">The event arguments.</param>
        private void CountrySelector_SelectedIndexChanged(object sender, Telerik.WinControls.UI.Data.PositionChangedEventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
     
            EulaInfo.Instance.SelectedCountry = this.CountrySelector.SelectedValue as Country;
            this.CountrySelector.DropDownListElement.ShowImageInEditorArea = true;
            this.CountrySelector.DropDownStyle = Telerik.WinControls.RadDropDownStyle.DropDownList;
             
            try
            {
                Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("SharePointProductInstaller.Eula." + EulaInfo.Instance.SelectedCountry.EulaID);
                this.EulaReader.LoadDocument(stream);
                this.AgreeEulaActor.Checked = EulaInfo.Instance.Accepted;
                this.DisagreeEulaActor.Checked = !EulaInfo.Instance.Accepted;
                this.btnPrintActor.Enabled = true;
                this.AgreeEulaActor.Enabled = true;
                this.DisagreeEulaActor.Enabled = true;
            }
            catch (Exception ex)
            {
                //throw ex;
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }
     
        /// <summary>
        /// Changes the DropDonwList style for text input (autocomplete mode).
        /// </summary>
        /// <param name="sender">The DropDownList instance.</param>
        /// <param name="e">The event arguments.</param>
        private void CountrySelector_MouseClick(object sender, MouseEventArgs e)
        {
            this.CountrySelector.DropDownStyle = Telerik.WinControls.RadDropDownStyle.DropDown;
            this.CountrySelector.DropDownListElement.ShowImageInEditorArea = false;
        }
     
        /// <summary>
        /// Checks and update DropDownList selected item when leaving.
        /// This is needed if control lost focus and no item was selected after entering text.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CountrySelector_Leave(object sender, EventArgs e)
        {
            if (this.CountrySelector.SelectedValue != null && this.CountrySelector.Text != ((Country)this.CountrySelector.SelectedValue).CountryName)
            {
                var matchedItem = this.CountrySelector.Items.First(x => x.Text == this.CountrySelector.Text);
                if (matchedItem != null)
                    matchedItem.Selected = true;
                else
                {
                    this.CountrySelector.Text = "";
                    this.CountrySelector.SelectedItem = null;
                }
            }
        }
     
        private void Localize()
        {
            this.lCountryInfoHeadline.Text = Properties.Resources.EulaStepTitle;
            this.CountrySelector.NullText = Properties.Resources.CountrySelectorNullText;
            this.DisagreeEulaActor.Text = Properties.Resources.DisagreeEulaActorText;
            this.AgreeEulaActor.Text = Properties.Resources.AgreeEulaActorText;
            this.btnPrintActor.Text = Properties.Resources.btnPrintActorText;
        }
     
        #endregion
    }

    Regards,
    Ralf
  2. George
    Admin
    George avatar
    500 posts

    Posted 27 Jan 2014 Link to this post

    Hello Ralf,

    Thank you for contacting us.

    Yes, the SelectedIndexChanged event should be fired only when an item is actually selected. Also I saw in your DoWork event of the BackgroundWorker that you are accessing the properties of RadListDataItem and modifying them. Since the data item is tightly connected to the control and its visual items, it is not recommended to modify it in another thread. This can cause issues, such as not correct firing of an event and other undesired behavior. I recommend you to read the following article which shows how to use Multithreading with RadGridView, but is applicable to other RadControls. Also pay attention to the articles at the bottom of the article: Combining Multithreading with RadGridView.

    Let me know if you have further questions.

    Regards,
    George
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINFORMS.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Ralf
    Ralf avatar
    77 posts
    Member since:
    Jun 2012

    Posted 27 Jan 2014 in reply to George Link to this post

    Hello George,

    if the SelectedIndexChanged event not be fired when only one item matching my input and the DropDownBox closing automatically, how to act with this? I think this is a bug because the user connot select this item.

    Best regards,
    Ralf
  5. George
    Admin
    George avatar
    500 posts

    Posted 30 Jan 2014 Link to this post

    Hi Ralf,

    Thank you for replying.

    This is a normal behavior and our RadDropDownList is designed this way, since the standard ComboBox has the very same behavior. The SelectedIndexChanged event will only be fired after an item is actually selected, instead of just typed in. If you want to select such item you will need to press the Enter key or manually set the Selected property of the item.

    Moreover, keep in mind that this property will have effect only if the item has a valid RadDropDownList parent, i.e. it must be added to the Items collection. Also setting this property from another thread can result in unexpected results and I recommend you to apply the articles I provided you with in my previous reply.

    I hope this helps.

    Regards,
    George
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - APPLICATION ANALYTICS for WINFORMS.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  6. Ralf
    Ralf avatar
    77 posts
    Member since:
    Jun 2012

    Posted 30 Jan 2014 in reply to George Link to this post

    Hello George,

    thank you for information.

    ok, it's a normal behavior. But is this ok for a user?

    For example the user types in "Ger".
    The autocomplete functionality will find two items and Show them to the user. The user can select one and all is fine.

    But when the user types in "Germany" only one item will be found. The Dropdown box closing automatically and the user don't know why. Normally the user think there are no matches for "Germany" and he cannot work on. Bad application....
    But if the Dropdown box will be left open also if only one item matches, the user can see there is a match and he can work on be select this item. Please mind not all users are familiar with interaction concepts of complex controls.

    Only as suggestion :-)

    I'm using the BackgroundManager only for initial data loading and RadListItem creation. The items will be added to the control in ProgressChanged event handling method. All changes to the items will be done after that.

    Best regards,
    Ralf
  7. George
    Admin
    George avatar
    500 posts

    Posted 03 Feb 2014 Link to this post

    Hello Ralf,

    Thank you for replying.

    We try to be consistent with the standard .NET controls as is in this case. If you want to change the default behavior you can simply cancel the closing of the Popup:
    this.radDropDownList.DropDownListElement.AutoCompleteSuggest.DropDownList.PopupClosing += DropDownList_PopupClosing;
     
    void DropDownList_PopupClosing(object sender, RadPopupClosingEventArgs args)
    {
        RadDropDownListElement element = sender as RadDropDownListElement;
        if (element != null && element.Items.Count == 1 && args.CloseReason == RadPopupCloseReason.CloseCalled)
        {
            args.Cancel = true;
        }
    }

    This will allow the user to select the last item in the list.

    I hope this information helps. Should you have further questions, do not hesitate to ask.

    Regards,
    George
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - APPLICATION ANALYTICS for WINFORMS.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
Back to Top
UI for WinForms is Visual Studio 2017 Ready