Selected index combobox winforms - c#

Ok, very dumb question but i haven't really found an answer on internet.
I have multiple comboboxes on a form. The binding of each combobox is on form_load.
When the form loads, the first item is selected on the form. This is obvious, but I don't want this. So i used in the form_load the following code:
private void InvoiceView_Load(object sender, EventArgs e)
{
// Bind list of customers to combobox
CustomerComboBox.DataSource = invoicePresenter.getCustomers();
CustomerComboBox.DisplayMember = "CustomerName";
CustomerComboBox.ValueMember = "CustomerId";
// Bind list of products to combobox
productCombobox.DataSource = invoicePresenter.getProducts();
productCombobox.DisplayMember = "ProductName";
productCombobox.ValueMember = "ProductId";
// Bind list of vat codes to combobox
vatComboBox.DataSource = invoicePresenter.getTaxCodes();
vatComboBox.DisplayMember = "taxCodeShortDescr";
vatComboBox.ValueMember = "taxCodeId";
// Set comboboxes empty
CustomerComboBox.SelectedItem = null;
productCombobox.SelectedItem = null;
vatComboBox.SelectedItem = null;
}
This works. But the textboxes are still giving me the data of the first item ? My guess is because its in the selectedIndexChanged. But i have no clue what to use else.
If I put the combobox.selectedIndex = -1; I face the same issue.
the code:
private void CustomerComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// Bind the selected customer itemvalues to the texboxes
txtCustomerName.Text = ((tbl_customer)CustomerComboBox.SelectedItem).CustomerName.ToString();
txtAddress.Text = ((tbl_customer)CustomerComboBox.SelectedItem).CustomerAddress.ToString();
txtPostalCode.Text = ((tbl_customer)CustomerComboBox.SelectedItem).CustomerPostalCode.ToString();
txtCity.Text = ((tbl_customer)CustomerComboBox.SelectedItem).CustomerCity.ToString();
txtCountry.Text = ((tbl_customer)CustomerComboBox.SelectedItem).CustomerCountry.ToString();
txtVatNumber.Text = ((tbl_customer)CustomerComboBox.SelectedItem).CustomerCountryCode.ToString() + ((tbl_customer)CustomerComboBox.SelectedItem).CustomerVat.ToString();
}
One would think, because im using selecteditem in the textbox binding, it would be null also. But this is not the case.

Interestingly, seems like you've hit one of the WF data binding quirks. The problem is caused by the fact that the CurrencyManager class which maintains every list data source does not allow setting the Position property to -1 (thus Current to null) when the list count is not zero. Since the ComboBox is synchronizing the SelectedIndex with the CurrencyManager.Position, this effectively prevents having an unselected item.
As a workaround, if the data bound mode of the list portion is not essential for you, replace the line
CustomerComboBox.DataSource = invoicePresenter.getCustomers();
with
foreach (var customer in invoicePresenter.getCustomers())
CustomerComboBox.Items.Add(customer);
Do the same for the other comboboxes that need such behavior.

You can remove the handler for the SelectedIndex_Changed event of combobox, bind data, then add the handler back. like this :
private void InvoiceView_Load(object sender, EventArgs e)
{
this.CustomerComboBox.SelectedIndexChanged -= new EventHandler(CustomerComboBox_SelectedIndexChanged);
this.productCombobox.SelectedIndexChanged -= new EventHandler(productCombobox_SelectedIndexChanged);
this.vatComboBox.SelectedIndexChanged -= new EventHandler(vatComboBox_SelectedIndexChanged);
// Bind list of customers to combobox
CustomerComboBox.DataSource = invoicePresenter.getCustomers();
CustomerComboBox.DisplayMember = "CustomerName";
CustomerComboBox.ValueMember = "CustomerId";
// Bind list of products to combobox
productCombobox.DataSource = invoicePresenter.getProducts();
productCombobox.DisplayMember = "ProductName";
productCombobox.ValueMember = "ProductId";
// Bind list of vat codes to combobox
vatComboBox.DataSource = invoicePresenter.getTaxCodes();
vatComboBox.DisplayMember = "taxCodeShortDescr";
vatComboBox.ValueMember = "taxCodeId";
this.CustomerComboBox.SelectedIndexChanged += new EventHandler(CustomerComboBox_SelectedIndexChanged);
this.productCombobox.SelectedIndexChanged += new EventHandler(productCombobox_SelectedIndexChanged);
this.vatComboBox.SelectedIndexChanged += new EventHandler(vatComboBox_SelectedIndexChanged);
}

Related

Dynamic ComboBox Button Duplicating Data

I am experiencing a problem where I have a button to populates a FlowLayoutPanel. All works well, and the combobox is generated. However, there is a small bug in the data populating of the combobox. I have a Binding source set up from my database and I link to the combobox in the following manner. The data is populated as expected, however, when I create another combobox using the same button, it always fills it with the same selection of data as the combobox above or below. The bizarre occurrence also happens when I have many more comboboxes. Here is my code. Any suggestions?
private void additionalpartbtn_Click(object sender, EventArgs e)
{
string fieldname = "addpart";
int fieldnamecount = 0;
ComboBox newcombobox = new ComboBox();
newcombobox.Name = fieldname + fieldnamecount;
newcombobox.DataSource = sqlpartBindingSource;
newcombobox.DisplayMember = "part";
additionalpartspnl.Controls.Add(newcombobox);
ComboBox newsidecombobox = new ComboBox();
newsidecombobox.Name = "side" + fieldname + fieldnamecount;
newsidecombobox.DataSource = sqlsideBindingSource;
newsidecombobox.DisplayMember = "side";
newsidecombobox.Size = new System.Drawing.Size(40, 21);
additionalpartspnl.Controls.Add(newsidecombobox);
fieldnamecount++;
}

Autocomplete for DatagridView ComboBox

I have a data grid view which is used to bind values.
I have a ComboBox inside this DatagridView; I want to implement an auto complete property in this ComboBox. It should not only search for the first letter but the whole item...
This can be done by
Grabbing the ComboBox
Manipulating its Items
Let's assume you have only one ComboBoxColumn; then you can grab an instance of the current one like this:
ComboBox editCombo = null; // class level variable
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
editCombo = e.Control as ComboBox;
if (editCombo != null)
{
// here we can set its style..
editCombo.DropDownStyle = ComboBoxStyle.DropDown;
editCombo.AutoCompleteMode = AutoCompleteMode.Suggest;
// sigh..:
editCombo.TextChanged -= editCombo_TextChanged;
editCombo.TextChanged += editCombo_TextChanged;
}
}
Let's assume you have the valid list of values in a List<string>
List<string>() allChoices = new List<string>();
Then we can adapt the Items to be shown in the TextChanged event:
void editCombo_TextChanged(object sender, EventArgs e)
{
List<String> items = allChoices.Select(x=>x)
.Where(x=>x.Contains(editCombo.Text)).ToList();
if (items.Count > 0)
{
editCombo.Items.Clear();
editCombo.Items.AddRange(items.ToArray());
}
editCombo.Select(editCombo.Text.Length, 0); //clear the selection
}
Note that this x=>x.Contains(editCombo.Text) searches for items that contain the full text entered. I hope that is what you mean; searching for items that are identical to the entered text makes no sense, as then you do not need to AutoComplete them anyway..

ListBox deletion

I have a listbox, with 2 buttons, new and delete. new adds an item into the list box, and the delete button should delete the item out of the list box. The list box items are tied to a class that stores user entered data from text boxes below.
private void AddListBox()
{
lstCondition.BeginUpdate();
Condition cond = new Condition("");
cond.Name = string.Format("Condition {0}", _selection.NetConditions.Count + 1);
_selection.NetConditions.Add(cond);
lstCondition.EndUpdate();
lstCondition.SelectedItem = cond;
cboNetCondition.Properties.Items.Clear();
cboNetCondition.Properties.Items.AddRange(NetCondition);
cboControlType.Properties.Items.Clear();
cboControlType.Properties.Items.AddRange(ControlType);
cboFlowRate.Properties.Items.Clear();
cboFlowRate.Properties.Items.AddRange(FlowRate);
}
private void btnNew_Click(object sender, EventArgs e)
{
AddListBox();
}
the cbo items are comboboxes, whose data gets tied in the condition class to each instance of the list box.
public frmNetConditions(Condition condo, Selection selection)
{
InitializeComponent();
_selection = selection;
lstCondition.DataSource = _selection.NetConditions;
condition = _selection.NetConditions.Count;
}
private void btnDelete_Click(object sender, EventArgs e)
{
selectedCondition = (Condition)lstCondition.SelectedItem;
cboControlType.SelectedIndex = -1;
cboNetCondition.SelectedIndex = -1;
cboFlowRate.SelectedIndex = -1;
txtFlowRate.Text = string.Empty;
txtStatPressure.Text = string.Empty;
txtDampOpening.Text = string.Empty;
txtDensity.Text = string.Empty;
cboDensity.SelectedIndex = -1;
lstCondition.Items.Remove(lstCondition.SelectedItem);
lstCondition.Refresh();
}
After pressing this delete button, the listbox, still contains the item i wish to delete, im unsure why thats the case?
Update with datasource
public List<Condition> NetConditions { get { return _netconditions; } }
As already suggested, you should bind to a BindingList<Condition> instead of a List<Condition>. This allows you to change the datasource and the control (ListBox) to get notified by your changes. The code should look like this:
lstCondition.ValueMember = "ConditionId";
lstCondition.DisplayMember = "Name";
lstCondition.DataSource = NetConditions;
After defining the binding, the correct way of operating on the ListBox items is to remove from the datasource, not the ListBox itself:
// SelectedItem should be checked for null (no selection is an option)
NetCondition.Remove((Condition)lstCondition.SelectedItem);
However, if you plan to change properties from an element (so, not the list itself), the control is notified only if your element (Condition) implements INotifyPropertyChanged interface.

DevExpress lookupedit repository item add new row in Xtra Grid View in first row

I have a devexpress gridcontrol with 5 columns. The first column is a lookupedit repository with some data, let say with CarTypes.
To load data in grid I am using a BindingSource. In this BindingSource.DataSource I have load a IList<Cars>
and then
added this binding source in dataSource of my gridcontrol
like bellow
BindingSource _carsBindingSource = new BindingSource();
private void BindData(IList<Cars> data)
{
_carsBindingSource.DataSource = data;
carsGridControl.BeginUpdate();
carsGridControl.DataSource = _carsBindingSource;
carsGridControl.RefreshDataSource();
carsGridControl.EndUpdate();
}
I have a button to add new line in my grid "Add new car" and add a new line in _carBindingSource
private void AddNewRow()
{
_newRow = true;
_carsBindingSource.AllowNew = true;
Cars newCar = new Cars();
newCar.CarType = new CarType();
_carsBindingSource.Add(newCar );
//_carsBindingSource.Insert(0,newCar);
}
Now I want to add the new line in the first row of grid.
I use Insert
_carsBindingSource.Insert(0,newCar);
But it didn't work. The lookupedit repository can't load data.
With _carsBindingSource.Add(newCar); it works fine
Can anyone help me? Thank you!
If you haven't already, consider using an intermediate list for your car types:
private List<CarTypes> _CarTypes;
// Elsewhere in the code...
_CarTypes = GetCarTypes();
And then in the form load event, be sure this is bound to the data source:
repositoryLookupItemCarTypes.DataSource = _CarTypes;
With this, the grid should now automatically manage the instantiation and selection of the CarType object for each Cars object. You can omit this line when you add a car to the grid:
newCar.CarType = new CarType();
In the designer, I think it helps to alter the DisplayMember Property of the repository Item.
With this setup, any Car added to your grid should automatically have the CarType as a populated Lookup Edit.
If any of this is unclear, let me know. I did a quick and dirty solution to test this, and I obviously can't post it all, but I can tell you it did work with both Add and Insert.
Actualy I found a solutions.
The problem was in GridView_CustomRowCellEdit(object sender, CustomRowCellEditEventArgs e) event
where I change the AllowEdit value (e.Column.OptionsColumn.AllowEdit = true;).
private void gridView_CustomRowCellEdit(object sender, CustomRowCellEditEventArgs e)
{
string cName = e.Column.FieldName;
GridView gv = sender as GridView;
if (cName == "CarType.IdApi")
{
if (isNewRow)
{
Cars cars= (Cars)gv.GetRow(e.RowHandle);
int a = e.RowHandle;
if (cars.ID== 0 && e.RowHandle == 0)
{
e.Column.OptionsColumn.AllowEdit = true;
}
else
{
e.Column.OptionsColumn.AllowEdit = false;
}
}
}
}
When I use Insert(0, new Car) then because of second row whitch has value
the AllowEdit was false;
So I remove else code and it works
private void gridView_CustomRowCellEdit(object sender, CustomRowCellEditEventArgs e)
{
string cName = e.Column.FieldName;
GridView gv = sender as GridView;
if (cName == "CarType.IdApi")
{
if (isNewRow)
{
Cars cars= (Cars)gv.GetRow(e.RowHandle);
int a = e.RowHandle;
if (cars.ID== 0 && e.RowHandle == 0)
{
e.Column.OptionsColumn.AllowEdit = true;
}
}
}
}
So finlay I found that bindingSource.Add(object) and bindingSource.Insert(0,object) is same!
I apologize for my english!!

how to dynamically add combobox in windows forms(C#) and bound it to a column of a table in sql database

My windows form has an ADD button which adds a combo box to the form after each click. The problem is, i am not able to bind it to a table column at run time. Using an existing databinding source selects the same value in all the combo boxes. I am coding in C#
here is the sample code :
ComboBox ocbNext = new ComboBox();
//HAVE set the rest of the properties right, the problem is with the databinding
ocbNext.DataSource = this.dummysubjectBindingSource;
ocbNext.DisplayMember = "sub_name";
ocbNext.ValueMember = "sub_name";
this.Controls.Add(ocbNext);
I added a DataSet to the solution and droped the Employees table (from Northwind) in the designer, which automatically created the employeesBindingSource. I dropped a combobox and a button on the Form and I set the DataSource and DataMember of the combo. Then I handled some events:
private void Form1_Load(object sender, EventArgs e)
{
this.employeesTableAdapter.Fill(this.dS.Employees);
}
private int _i = 0;
private void button1_Click(object sender, EventArgs e)
{
ComboBox combo = new ComboBox();
combo.DataSource = this.employeesBindingSource;
combo.DisplayMember = this.dS.Tables[0].Columns[++_i].ColumnName;
combo.Location = new Point(comboBox1.Location.X, comboBox1.Location.Y + comboBox1.Height * _i);
this.Controls.Add(combo);
}
So on each click, a new combo is added onto the form dynamically right under the previous combo. The combo is also bound to the next column in the Employees table (no boundary checks however).
As you can see, this is pretty easy stuff. Hope this helps.
Okay, so here is a variation of the code that could help you with that other question you asked in the comments of this answer.
It assumes you have a Form with a button and a DataSet with table Employees. On button click it creates a combo, and fills it with data (the Name column of Employees). Each time you add a combo, it gets its own copy of the data (this is important to be able to remove items from one combo at a time). Then, every time you select a value in the combo, the combo is disabled and the other combos don't have that selected value in their list.
private int _i = 0;
private void button1_Click(object sender, EventArgs e)
{
DataSet dataS = dS.Clone();
this.employeesTableAdapter.Fill((DS.EmployeesDataTable)dataS.Tables[0]);
BindingSource bindSource = new BindingSource(dataS, "Employees");
ComboBox combo = new ComboBox();
combo.Name = this.dS.Tables[0].Columns[0].ColumnName + (++_i).ToString();
combo.DataSource = bindSource;
combo.DisplayMember = this.dS.Tables[0].Columns[1].ColumnName; //This column is the Name of Employee
combo.Location = new Point(button1.Location.X, button1.Location.Y + combo.Height * _i);
combo.SelectedIndexChanged += new EventHandler(comboBox_SelectedIndexChanged);
this.Controls.Add(combo);
}
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (Control ctrl in this.Controls)
{
if (ctrl is ComboBox && ctrl != sender && ctrl.Enabled)
{
((BindingSource)((ComboBox)ctrl).DataSource).RemoveAt(((ComboBox)sender).SelectedIndex);
}
}
((ComboBox)sender).Enabled = false;
}
This is pretty close to what you require, or easily adaptable to meet your expectations. Enjoy and please select an answer as the accepted one. Thanks!
Option 1: Fill the combobox with strings:
this.comboBox1.Items.Add("Syed");
this.comboBox1.Items.Add("Baqar");
Option 2: Fill the combobox with an array of strings:
this.comboBox1.Items.AddRange(new object[] { "Syed", "Baqar" });
You need to add controls to the parent window first, and then set the data source.
ComboBox ocbNext = new ComboBox();
this.Controls.Add(ocbNext);
ocbNext.DisplayMember = "sub_name";
ocbNext.ValueMember = "sub_name";
ocbNext.DataSource = this.dummysubjectBindingSource;
Should be fine if you create a new local ComboBox variable in the clickevent. If you use a global variable for the ComboBox this might explain your problems. But without a sample how you're doing it's hard to see what's really happening, so think this is just a rough guess

Categories