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

问题描述 投票:0回答:2

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

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

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

这是我的代码:

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 上看到了这一点:防止 System.Window.Forms.ComboBox (C#) 的 AutoSelect 行为

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

c# winforms combobox
2个回答
1
投票

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

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

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

Cbo_ProductGroup.Text = searchText;

在这种情况下,会触发一个新事件

Text_Changed
,因此应用程序具有无限循环。所以我使用了一个属性 (
ShouldTextChangedEventBeIgnored
),如果
Text_Changed
事件应该被忽略。 感谢@CaiusJard 在评论中提供的许多提示。

这是我的最终代码:

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

0
投票

感谢这个解决方案。不过上线了

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

我收到错误“无法将匿名方法块转换为类型‘type’,因为它不是委托类型”

如果我尝试使用另一种方法,则会出现此错误“无效的跨线程操作:控件'Cbo_ProductGroup'是从创建它的线程以外的线程访问的。”

我该如何解决这个问题?

© www.soinside.com 2019 - 2024. All rights reserved.