C# - Winforms - Combobox - 避免选择更新数据源的第一项

Posted

技术标签:

【中文标题】C# - Winforms - Combobox - 避免选择更新数据源的第一项【英文标题】:C# - Winforms - Combobox - Avoid selecting the first item updating the datasource 【发布时间】:2022-01-08 15:59:27 【问题描述】:

我的应用程序中有一个组合框,根据您可以在文本字段中输入的搜索文本,异步加载项目。

这工作正常,但每次在更新组合框的数据源期间自动选择第一项的文本。

这会导致意外行为,因为我需要让用户输入的搜索文本留在组合框的文本字段中,直到用户完成选择并且不会自动用第一个条目覆盖文本。

这是我的代码:

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;
            
        
    

我尝试设置Cbo_ProductGroup.SelectedIndex = -1,但这并不能解决我的问题。

我也在 SO 上看到了这个:Prevent AutoSelect behavior of a System.Window.Forms.ComboBox (C#)

但是对于这个问题真的没有更简单的解决方案吗?

【问题讨论】:

您是否尝试制作由数据库驱动的自动完成功能? 这会导致意外行为 - 通常在 winforms 中,如果我们以编程方式设置文本框的文本但又不想触发文本更改处理程序,我们也删除事件处理程序,执行操作并恢复处理程序,或者(我的偏好)我们设置一些 bool "ignoreTextChanged" true 并且在 TextChanged 处理程序中,我们做的第一件事是检查 bool 并将其设置为 false 并返回,如果它是 true @CaiusJard 第一个问题。我不想提前将所有数据加载到控件中然后使用自动完成,因为我们里面有很多数据。通过给定的文本输入加载它们是有意义的。 @CaiusJard 对于您的第二条评论:我不确定这是否适合这种情况。首先更改文本,然后异步加载项目。这正是选择第一个项目的时间。我不确定我是否正确理解了您,但在我看来,这与 Text_Changed 事件本身无关。它用第一个加载条目的文本覆盖用户输入的文本。 捕获用户输入的文本,加载项目,恢复文本。 f 您通过更改文本触发加载项目,然后在恢复文本之前设置 ignoreTextChanged=true (如果恢复 txt 再次触发搜索)。您可能还想捕获插入符号的位置,以便您也可以恢复它.. 过去我用两个控件(例如一个文本框和一个列表框)完成了这项工作,这样它们就不会互相争斗 【参考方案1】:

我现在开始工作了。 当我删除组合框文本字段的绑定时,它起作用了

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

并将新(旧)值直接设置为组合框的文本字段。

Cbo_ProductGroup.Text = searchText;

在这种情况下,一个新事件Text_Changed 被触发,因此应用程序有一个无限循环。所以我使用了一个属性(ShouldTextChangedEventBeIgnored),如果Text_Changed 事件应该被忽略。 感谢 @CaiusJard 在 cmets 中提供的许多提示。

这是我的最终代码:

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);
         
    

【讨论】:

以上是关于C# - Winforms - Combobox - 避免选择更新数据源的第一项的主要内容,如果未能解决你的问题,请参考以下文章

在 C# .net winforms 中将字典绑定到 ComboBox

C# winfrom comboBox

C# WinForms TextBox 等的垂直对齐

C# Combobox (Dropdownstyle = Simple) -- 如何在键入时选择项目

如何禁用 C# 组合框中元素的编辑?

WinForms ComboBox DropDown 和 Autocomplete 窗口都出现