Reputation: 2931
First: I have List that filled up with object type of Customer
List<Customer> Customers = new List<Customer>();
Second: I have 2 ComboBox, one for Customer Name and other for Customer Phone. And set both DataSource to Customers list.
CustomersPhone_ComBx.DataSource = Customers.Select(Customer => Customer.Phone).ToList();
CustomersName_ComBx.DataSource = Customers.Select(Customer => Customer.Name).ToList();
Third: When the user change selected item in Phone ComboBox, I want to filter the names in Name ComboBox Which is have the same Phone number it was selected. (Because it may be the phone number registered with more than one name). I have this code
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();
}
But when I test it and change selected item in Phone ComboBox nothing change in Name ComboBox.
Update 1
Fourth: If I used foreach
, it works fine like the following code, but don't work with 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);
}
Update 2
Theses properties of 2 ComboBox, they are the same.
// 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);
And the form named NewReceipt_Delivery_Form and these line how I show it.
NewReceipt_Delivery_Form NewReceipt_Delivery_Form = new NewReceipt_Delivery_Form();
NewReceipt_Delivery_Form.ChangeUI();
NewReceipt_Delivery_Form.ShowDialog();
And ChangeUI method
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;
}
And the SelectedIndexChanged event as 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();
}
Upvotes: 3
Views: 5321
Reputation: 23732
With the new information about the properties of the comboboxes I could finally reproduce your problem. It seems that the Sorted
property is causing this problem:
this.CustomersName_ComBx.Sorted = true;
The solution is to set it to false
this.CustomersName_ComBx.Sorted = false;
to have the display still ordered, simply use OrderBy
when you initialize the DataSource
:
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 (sort of explanation) can be found on the documentation of the property Sorted
In the Remarks section it says:
This property specifies whether the ComboBox sorts existing entries and add new entries to the appropriate sorted position in the list. You can use this property to automatically sort items in a ComboBox. As items are added to a sorted ComboBox, the items are moved to the appropriate location in the sorted list.
I guess when you change the DataSource
the new element are simply put at the positions of the old ones. But the actual DataSource
has now less elements. You can check it in the debugger. The count of DataSource
will be less after the filtered collection has been assigned!
My second guess would be that if you set Sorted = true
it actually ignores the DataSource
collection after the initial initialization and from this moment on it only displays what is in the Items
collection. The debugger shows that Items.Count
remains the same after the filtered DataSource
has been assigned, but DataSource.Count
has changed. This seems some sort of an ambiguous state.
You cannot modify the Items
collection because the ComboBox
is data bound but you cannot display the DataSource
because the Sorted
is set to true. Actually the remarks say that:
Attempting to set the Sorted property on a data-bound control raises an ArgumentException. You must sort the data using the underlying data model.
But it does not say what happens when you set it before the binding!
Upvotes: 3
Reputation: 266
Here is solution that worked for me, only difference is that i've used CustomersPhone_ComBx.SelectedItem instead of its text property.
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; }
}
Upvotes: 0