简体   繁体   中英

C# - Winforms - Combobox - Avoid selecting the first item updating the datasource

I have a question regarding C# Winforms. I think, it is a beginner one, but I can't figure it out. I'm having a combobox in my application, which items are loaded asynchronously depending on the search text you can enter in the text field. This works fine, but actually I'm having the issue, that every time the text of the first item is automatically selected during updating the datasource of the combobox. This lead to unintended behaviour, because I need to have the search text entered by the user to stay in the textfield of the combobox until a selection is done by the user and not automatically overwrite the text with the first entry. This is my code:

public partial class ProductGroupDescription : UserControl, Interfaces.TabPages.ITabPageProductGroupDescription
{
    private Services.IProductGroupDescriptionService _ApplicationService;

    public BindingList<ProductGroup> ProductGroups { get; set; } = new BindingList<ProductGroup>();
    public string ProductGroupSearchText { get; set; } = string.Empty;

    public ProductGroupDescription(Services.IProductGroupDescriptionService applicationService)
    {
        InitializeComponent();
        InitialSetupControls();
        _ApplicationService = applicationService;
    }

    public void InitialSetupControls()
    {
        var pgBindingSource = new BindingSource();
        pgBindingSource.DataSource = ProductGroups;
        Cbo_ProductGroup.DataSource = pgBindingSource.DataSource;
        Cbo_ProductGroup.DataBindings.Add("Text", ProductGroupSearchText, "");
    }

    private async void Cbo_ProductGroup_TextChanged(object sender, EventArgs e)
    {
        if (Cbo_ProductGroup.Text.Length >= 2)
        {
            ProductGroupSearchText = Cbo_ProductGroup.Text;
            Cbo_ProductGroup.SelectedIndex = -1;
            bool withStopFlagged = Chk_StopFlag_PGs_Included.Checked;
            List<ProductGroup> list = await _ApplicationService.GetProductGroupBySearchString(ProductGroupSearchText, withStopFlagged);
            if (list != null && list.Count > 0)
            {
                ProductGroups.Clear();
                list.ForEach(item => ProductGroups.Add(item));
                Cbo_ProductGroup.DroppedDown = Cbo_ProductGroup.Items.Count > 0 && Cbo_ProductGroup.Focused;
            }
        }
    }
}

I already tried to set Cbo_ProductGroup.SelectedIndex = -1 , but it does not solve my issue here.

I also saw this on SO: Prevent AutoSelect behavior of a System.Window.Forms.ComboBox (C#)

But is there really no simpler solution to this issue? Do I really need to write a such complex extension method to this simple requirement? Many thanks in advance.

I got it to work now. It worked, when I removed the binding of the text field of the combobox

Cbo_ProductGroup.DataBindings.Add("Text", ProductGroupSearchText, "");

and set the new (old) value directly to the text field of the combobox.

Cbo_ProductGroup.Text = searchText;

In this case, a new event Text_Changed is fired and so the application has a infinite loop. So I used a property ( ShouldTextChangedEventBeIgnored ), if the Text_Changed event should be ignored. Thanks to @CaiusJard for many hints in the comments.

This is my final code:

public partial class ProductGroupDescription : UserControl, Interfaces.TabPages.ITabPageProductGroupDescription
{
    private ApplicationLogic.Interfaces.Services.IProductGroupDescriptionService _ApplicationService;

    public BindingList<ProductGroup> ProductGroups { get; set; } = new BindingList<ProductGroup>();
    public bool ShouldTextChangedEventBeIgnored { get; set; } = false;

    public ProductGroupDescription(ApplicationLogic.Interfaces.Services.IProductGroupDescriptionService applicationService)
    {
        _ApplicationService = applicationService;
        InitializeComponent();
        InitialSetupControls();
    }

    public void InitialSetupControls()
    {
        var pgBindingSource = new BindingSource();
        pgBindingSource.DataSource = ProductGroups;
        Cbo_ProductGroup.DataSource = pgBindingSource.DataSource;
    }

    private async Task<List<ProductGroup>> LoadProductGroupItems(string searchText)
    {
        bool withStopFlagged = Chk_StopFlag_PGs_Included.Checked;
        return await _ApplicationService.GetProductGroupBySearchString(searchText, withStopFlagged);
    }

    private async Task SetProductGroupSearchBoxItems(List<ProductGroup> list, string searchText)
    {
        await Task.Run(() =>
        {
            if (list != null && list.Count > 0)
            {
                ShouldTextChangedEventBeIgnored = true;
                Cbo_ProductGroup.Invoke((c) =>
                {
                    ProductGroups.Clear();
                    list.ForEach(item => ProductGroups.Add(item));
                    c.DroppedDown = c.Items.Count > 0 && c.Focused;
                    c.Text = searchText;
                    c.Select(c.Text.Length, 0);
                });
                ShouldTextChangedEventBeIgnored = false;
            }
        });
    }

    private async void Cbo_ProductGroup_TextChanged(object sender, EventArgs e)
    {
        try
        {
            if (Cbo_ProductGroup.Text.Length >= 2 && ShouldTextChangedEventBeIgnored == false)
            {
                string searchText = Cbo_ProductGroup.Text;
                List<ProductGroup> list = await LoadProductGroupItems(Cbo_ProductGroup.Text);
                await SetProductGroupSearchBoxItems(list, searchText);
            }
        }
        catch(Exception ex)
        {
            System.Diagnostics.Trace.Write(ex);
        } 
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM