添加到 ToolStripDropDown 时列表框数据源不起作用

Listbox DataSource not working when added to a ToolStripDropDown

虽然我找不到解决方案,但我整天都在为这个问题苦苦挣扎。很抱歉post,我尽量简洁明了

这是可行的:我创建了一个 Form 并在其 class 中动态创建了一个 ListBox 并设置了它的 DataSourceDataTable 如下:

public partial class FrmAddress : Form
{
    private ListBox listBox1 = new ListBox();

    public FrmAddress()
    {
        this.InitializeComponent();

        [...]

        this.Controls.Add(listBox1);
    }

    [...]

    private void Load_Countries()
    {
        this.listBox1.DataSource = dtCountries;
        this.listBox1.DisplayMember = "Country";
        this.listBox1.ValueMember = "Country_ID";
    }

    [...]
}

这不起作用:创建自定义控件(继承自ToolStripDown),创建ToolStripControlHost(listBox1)的新实例,将该实例添加到ToolStripDown。将 listBox1.DataSource 设置为 DataTable。当显示 ToolStripDown 时,列表框在那里但为空(不显示数据源内容)。

public class CtlDropdownPopup : ToolStripDropDown
{
    ListBox controlToPop;
    ToolStripControlHost controlHost;

    public CtlDropdownPopup(ListBox controlToPop)
    {
        this.controlToPop = controlToPop;
        this.controlToPop.Location = Point.Empty;

        this.controlHost = new ToolStripControlHost(this.controlToPop);

        [...]

        this.Items.Add(this.controlHost);
    }
}

public class CtlCombobox : ComboBox
{
    private readonly CtlDropdownPopup suggestionDropDown;
    private readonly ListBox suggestionList = new ListBox();

    public CtlCombobox()
    {
        this.suggestionDropDown = new CtlDropdownPopup(this.suggestionList);
    }

    public void Source(DataTable dt, string display, string value)
    {
        this.suggestionDT = dt;

        this.suggestionList.DataSource = dt;
        this.suggestionList.DisplayMember = display;
        this.suggestionList.ValueMember = value;
    }
}

自定义 CtlDropdownPopup 被称为:(简化)

private CtlCombobox LstCountry;
this.LstCountry.Source(dtCountries, "Country", "Country_ID");

正如我所说,ToolStripDropDown 显示为其中包含 listBox1,但列表是空的。奇怪的是,如果我将 Source() 方法修改为

    public void Source(DataTable dt, string display, string value)
    {
        this.suggestionDT = dt;

        // this.suggestionList.DataSource = dt;
        // this.suggestionList.DisplayMember = display;
        // this.suggestionList.ValueMember = value;

        if (this.suggestionList != null)
        {
            foreach (DataRow row in dt.Rows)
            {
                this.suggestionList.Items.Add(row[display].ToString());
            }
        }
    }

列表框显示了上面的项目。虽然这个变通办法可以解决问题,但找不到为什么我不能直接设置 DataSource 的答案(就像我在第一个示例中直接设置的那样),而是必须手动添加项目,这很烦人。

任何想法都会真正帮助我今晚睡个好觉:)

想法 #1: 我相信因为相同的 dtCountries 链接到其他 ComboBox1.DataSource,这可能是问题所在,所以我设置 this.controlToPop.DataSource = dt.Copy(); 希望 "it is not somehow linked to the combobox",但问题仍然存在。

旁注:我正在尝试创建一个自定义组合框,建议 DataTable 中的项目。

想法来自 https://www.codeproject.com/Tips/789705/Create-combobox-with-search-and-suggest-list

您需要设置ListBox的BindingContext 属性。

当 ListBox (或任何控件) 添加到窗体时,它会从窗体继承其 BindingContext 属性。现在,由于您将 ListBox 添加到另一个带有 .BindingContext == nullTopLevel 控件,它不会从表单继承 属性,因此,它没有 BindingContext.

您可以通过为 ListBox 创建一个新的 BindingContext 来简单地避免这个问题:

public void Source(DataTable dt, string display, string value)
{
    this.suggestionDT = dt;

    this.suggestionList.BindingContext = new BindingContext();  // <<<<<<<<<<<<<
    this.suggestionList.DataSource = dt;
    this.suggestionList.DisplayMember = display;
    this.suggestionList.ValueMember = value;
}

您也可以从表单中复制 BindingContext 而不是 (通过 CtlCombobox 控件或将其作为参数传递).

希望对您有所帮助。