【问题标题】:ComboBox DataSource Dynamically ChangeComboBox 数据源动态变化
【发布时间】:2018-07-19 09:14:04
【问题描述】:

首先:我有 List 填充了 Customer

的对象类型
List<Customer> Customers = new List<Customer>();

第二:我有 2 个 ComboBox,一个用于 Customer Name,另一个用于 Customer Phone。并将 DataSource 设置为 Customers 列表。

CustomersPhone_ComBx.DataSource = Customers.Select(Customer => Customer.Phone).ToList();
CustomersName_ComBx.DataSource = Customers.Select(Customer => Customer.Name).ToList();

第三:当用户更改 Phone ComboBox 中的选定项目时,我想过滤 Name ComboBox 中的名称,该名称与选择的电话号码相同。 (因为可能是注册了多个名字的电话号码)。我有这个代码

private void CustomersPhone_ComBx_Leave(object sender, EventArgs e)
{
    if (CustomersPhone_ComBx.Text != "")
         CustomersName_ComBx.DataSource = Customers.Where(Customer => Customer.Phone == CustomersPhone_ComBx.Text).Select(Customer => Customer.Name).ToList();
    else
         CustomersName_ComBx.DataSource = Customers.Select(Customer => Customer.Name).ToList();
}

但是当我测试它并更改 Phone ComboBox 中的选定项目时,Name ComboBox 中没有任何变化。


更新 1

第四:如果我使用foreach,它可以像下面的代码一样正常工作,但不适用于DataSource

private void CustomersPhone_ComBx_SelectedIndexChanged(object sender, EventArgs e)
{
    List<Customer> FilteredCustomers = Customers
                       .Where(Customer => Customer.Phone == CustomersPhone_ComBx.Text).ToList();

    foreach (Customer C in FilteredCustomers)
        CustomersName_ComBx.Items.Add(C.Name);
}

更新 2

2个ComboBox的这些属性,它们是一样的。

        // CustomersName_ComBx
        // 
        this.CustomersName_ComBx.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
        this.CustomersName_ComBx.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
        this.CustomersName_ComBx.Dock = System.Windows.Forms.DockStyle.Fill;
        this.CustomersName_ComBx.Font = new System.Drawing.Font("Janna LT", 12F, System.Drawing.FontStyle.Bold);
        this.CustomersName_ComBx.FormattingEnabled = true;
        this.CustomersName_ComBx.Location = new System.Drawing.Point(0, 65);
        this.CustomersName_ComBx.Margin = new System.Windows.Forms.Padding(0, 7, 0, 0);
        this.CustomersName_ComBx.Name = "CustomersName_ComBx";
        this.CustomersName_ComBx.Size = new System.Drawing.Size(583, 46);
        this.CustomersName_ComBx.Sorted = true;
        this.CustomersName_ComBx.TabIndex = 52;
        // 
        // CustomersPhone_ComBx
        // 
        this.CustomersPhone_ComBx.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
        this.CustomersPhone_ComBx.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
        this.CustomersPhone_ComBx.Dock = System.Windows.Forms.DockStyle.Fill;
        this.CustomersPhone_ComBx.Font = new System.Drawing.Font("Janna LT", 12F, System.Drawing.FontStyle.Bold);
        this.CustomersPhone_ComBx.FormattingEnabled = true;
        this.CustomersPhone_ComBx.Location = new System.Drawing.Point(0, 7);
        this.CustomersPhone_ComBx.Margin = new System.Windows.Forms.Padding(0, 7, 0, 0);
        this.CustomersPhone_ComBx.Name = "CustomersPhone_ComBx";
        this.CustomersPhone_ComBx.Size = new System.Drawing.Size(583, 46);
        this.CustomersPhone_ComBx.Sorted = true;
        this.CustomersPhone_ComBx.TabIndex = 51;
        this.CustomersPhone_ComBx.SelectedIndexChanged += new System.EventHandler(this.CustomersPhone_ComBx_SelectedIndexChanged);

还有名为 NewReceipt_Delivery_Form 的表单以及我如何显示它。

NewReceipt_Delivery_Form NewReceipt_Delivery_Form = new NewReceipt_Delivery_Form();
NewReceipt_Delivery_Form.ChangeUI();
NewReceipt_Delivery_Form.ShowDialog();

ChangeUI方法

private List<Customer> Customers = new List<Customer>();
public void ChangeUI()
{
    OleDbCommand SelectCustomersCMD = new OleDbCommand("SELECT * FROM Customers ORDER BY [ID] ASC", Program.GeneralConnection);
    OleDbDataReader SelectCustomersREAD = SelectCustomersCMD.ExecuteReader();
    while (SelectCustomersREAD.Read())
    {
        Customer Customer = new Customer();
        Customer.ID = Convert.ToInt32(SelectCustomersREAD[0].ToString());
        /* And so on. */
        Customers.Add(Customer);
    }
    SelectCustomersREAD.Close();
    CustomersPhone_ComBx.DataSource = Customers.Select(Customer => Customer.Phone).ToList();
    CustomersName_ComBx.DataSource = Customers.Select(Customer => Customer.Name).ToList();
    CustomersPhone_ComBx.SelectedIndex = -1;
    CustomersName_ComBx.SelectedIndex = -1;
}

SelectedIndexChanged 事件为Aleksandar's answer

private void CustomersPhone_ComBx_SelectedIndexChanged(object sender, EventArgs e)
{
    string selectedPhone = (string)CustomersPhone_ComBx.SelectedItem;
    if (!String.IsNullOrEmpty(selectedPhone))
        CustomersName_ComBx.DataSource = Customers.Where(Customer => Customer.Phone == selectedPhone).Select(Customer => Customer.Name).ToList();
    else
        CustomersName_ComBx.DataSource = Customers.Select(Customer => Customer.Name).ToList();
}

【问题讨论】:

  • 你测试了这两种情况吗? if (DeliveryPhone_ComBx.Text != "") 两者的结果一样吗?
  • 你是如何测试它的?你设置断点检查是否CustomersPhone_ComBx_Leave?被执行了吗?
  • 是的,没有区别。无论情况如何,它仍然具有相同的 DataSource。如果我在 if 语句 之前添加这一行 CustomersName_ComBx.DataSource = null;,我找不到任何项目。
  • @MongZhu 是的,if语句完全没有问题。
  • 您确定要休假而不是CustomersPhone_ComBx.selectedindexchanged?

标签: c# winforms combobox


【解决方案1】:

有了关于组合框属性的新信息,我终于可以重现您的问题了。似乎是 Sorted 属性导致了这个问题:

this.CustomersName_ComBx.Sorted = true;

解决办法是设置为false

this.CustomersName_ComBx.Sorted = false;

要让显示仍然有序,只需在初始化DataSource 时使用OrderBy

CustomersPhone_ComBx.DataSource = Customers.Select(Customer => Customer.Phone)
                                           .OrderBy(x=>x).Distinct().ToList();
CustomersName_ComBx.DataSource  = Customers.Select(Customer => Customer.Name)
                                           .OrderBy(x => x).ToList();

A(某种解释)可以在属性 Sorted 的文档中找到

在备注部分它说:

此属性指定 ComboBox 是否对现有条目进行排序并添加新条目到列表中的适当的排序位置。您可以使用此属性自动对 ComboBox 中的项目进行排序。当项目添加到排序的 ComboBox 时,项目将移动到排序列表中的适当位置。

我猜当你更改 DataSource 时,新元素只是简单地放在旧元素的位置。但是实际的DataSource 现在元素更少了。您可以在调试器中检查它。分配过滤后的集合后,DataSource 的计数将减少!

我的第二个猜测是,如果您设置Sorted = true,它实际上会在初始初始化后忽略DataSource 集合,并且从此刻开始它只显示Items 集合中的内容。调试器显示Items.Count 在分配过滤后的DataSource 后保持不变,但DataSource.Count 已更改。这似乎是一种模棱两可的状态。 您无法修改Items 集合,因为ComboBox 是数据绑定的,但您无法显示DataSource,因为Sorted 设置为true。其实言论是这样说的:

尝试在数据绑定控件上设置 Sorted 属性会引发 ArgumentException。您必须使用底层数据模型对数据进行排序。

但它并没有说明当您设置它绑定之前会发生什么!

【讨论】:

  • 首先:当我使用Leave 事件时,确定它被触发了,因为我专注于另一个组合框“名称”。 Secode:我试过你的代码,也没有任何反应,断点停止在代码上,但组合框项没有区别!
  • @ShadyBoshra 那么我需要更多信息。您可以发布客户内容的样本吗?=!这样我就可以使用它了。到目前为止,我无法重现您的问题。我带了 3 个客户,2 个有相同的号码,当我选择双号时,名称组合框中只剩下 2 个
  • 我在您编辑后看到您的完整答案之前发表了评论。现在我明白了你所有的答案。谢谢?
  • @ShadyBoshra 非常欢迎您。这确实是一个有趣的问题。解决它很有趣。它再次表明,要弄清楚这些东西实际上需要多少信息。很酷,你提供了它;-) 干杯伙伴
  • 哦,对不起。我现在明白了,你的猜测可能是对的。
【解决方案2】:

这是对我有用的解决方案,唯一的区别是我使用了 CustomersPhone_ComBx.SelectedItem 而不是它的文本属性。

 public partial class Form1 : Form
 {
    public List<Customer> Customers { get; set; } = new List<Customer>
    {
        new Customer
        {
            Name = "John",
            Phone = "123"
        },
        new Customer
        {
            Name = "Mary",
            Phone = "123"
        },
        new Customer
        {
            Name = "Peter",
            Phone = "555"
        },
        new Customer
        {
            Name = "George",
            Phone = "222"
        },
        new Customer
        {
            Name = "Christine",
            Phone = "555"
        }
    };

    public Form1()
    {
        InitializeComponent();
        CustomersPhone_ComBx.DataSource = Customers.Select(Customer => Customer.Phone).ToList();
        CustomersName_ComBx.DataSource = Customers.Select(Customer => Customer.Name).ToList();
    }

    private void CustomersPhone_ComBx_SelectedIndexChanged(object sender, EventArgs e)
    {
        string selectedPhone = (string) CustomersPhone_ComBx.SelectedItem;
        if (!String.IsNullOrEmpty(selectedPhone))
            CustomersName_ComBx.DataSource = Customers.Where(Customer => Customer.Phone == selectedPhone).Select(Customer => Customer.Name).ToList();
        else
            CustomersName_ComBx.DataSource = Customers.Select(Customer => Customer.Name).ToList();
    }
}

public class Customer
{
    public string Name { get; set; }
    public string Phone { get; set; }
}

【讨论】:

  • 它对我不起作用,我不知道为什么!!请查看这些截图Before change DataSource ---- After change DataSource 谢谢
  • @ShadyBoshra 活动结束了吗?在事件的第一行放置调试停止会发生什么。
  • @LarsTech,我附上了 2 个用于调试停止的屏幕截图,在执行行之前和之后。 here
  • @ShadyBoshra 尝试在 CustomersPhone_ComBx_SelectedIndexChanged 的​​开头将 datasource 设置为 null
  • @ShadyBoshra 你介意分享你的表单的完整源代码吗?
猜你喜欢
  • 2019-06-07
  • 2010-10-05
  • 2012-11-10
  • 1970-01-01
  • 1970-01-01
  • 2015-12-11
  • 1970-01-01
  • 2019-07-23
相关资源
最近更新 更多