Can't programmatically set a ComboBox selection - c#

I am unable to programmatically set the selection in a ComboBox.
I try setting various properties (SelectedItem, SelectedText, SelectedIndex) but the ComboBox does not display the Name. The first row of the ComboBox, which is blank, is selected. The return value of the setting of the Property is correct.
What am I doing wrong?
...
this.bsConstructionContractors.DataSource = typeof(Contractor);
...
public partial class EditContractorDialog : Form
{
public EditContractorDialog(Contractor contractor)
{
InitializeComponent();
this.cmbEditContractorName.DataBindings.Add(new System.Windows.Forms.Binding("SelectedValue", projectView.bsProject, "ContractorId", true));
// new BindingSource is important here, so as to use a separate CurrencyManager
// because bsConstructionContractors is shared with another ComboBox on another form
this.cmbEditContractorName.DataSource = new BindingSource(projectView.bsConstructionContractors, null);
this.cmbEditContractorName.ValueMember = "ContractorId";
this.cmbEditContractorName.DisplayMember = "Name";
cmbEditContractorName.Enabled = true;
cmbEditContractorName.Focus();
// None of the following cause the ComboBox to display Contractor.Name
// The first entry in the ComboBox, which is a blank, is displayed
object myObject = cmbEditContractorName.SelectedItem = contractor;
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject: " + myObject.GetType()); // type is Contractor
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject: " + myObject); // myObject is the contractor
object myObject2 = cmbEditContractorName.SelectedText = contractor.Name;
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject2: " + myObject2.GetType()); // type is String
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject2: " + myObject2); // myObject2 is the contractor.Name
object myObject3 = cmbEditContractorName.SelectedIndex = 3; // arbitrary index, just to see if it would be selected
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject3: " + myObject3.GetType()); // type is Int32
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject3: " + myObject3); // myObject3 = 3
}
}
public partial class Contractor : System.IComparable
{
protected int id;
protected string name;
protected string licenseNumber;
protected Project project;
public virtual int ContractorId
{
get { return this.id; }
set { this.id = value; }
}
public virtual string Name
{
get { return this.name; }
set { this.name = value; }
}
public virtual string LicenseNumber
{
get { return this.licenseNumber; }
set
{ this.licenseNumber = value; }
}
public virtual int CompareTo(object obj)
{
if (!(obj is Contractor))
{
throw new System.InvalidCastException("This object is not of type Contractor");
}
return this.Name.CompareTo(((Contractor)obj).Name);
}
}

Use SelectedIndex finding the index by contractor name:
cmbEditContractorName.SelectedIndex = cmbEditContractorName.FindString(contractor.Name);

That is because you need to get an object reference to assign from the DataSource of the combobox itself.
Also for comboboxes I suggest you to use an ObservableCollection<T>.
cmbEditContractorName.DataSource = new ObservableCollection<Type>(your List<Type>);
cmbEditContractorName.SelectedItem = ((ObservableCollection<Type>)cmbEditContractorName.DataSource).FirstOrDefault(c=> c.yourProperty = "something"); // this will select the first item meeting your condition
Your code isn't working because you are assigning SelectedItem property with a reference of an object not existing in the combobox DataSource.

Related

set ComboBox selected item when another combobox changes the selected value c#

class ComboBoxCompany
{
public string Code;
public string Name;
public string Database;
public ComboBoxCompany(string code, string name, string database)
{
Code = code; Name = name; Database = database;
}
public override string ToString()
{
// Generates the text shown in the combo box
return Name;
}
}
class ComboBoxDatabase
{
public string cmpName;
public string dbName;
public ComboBoxDatabase(string cmpname, string dbname)
{
cmpName = cmpname; dbName = dbname;
}
public override string ToString()
{
// Generates the text shown in the combo box
return cmpName + " - " + dbName;
}
}
these are the classes for the 2 comboboxes, so when i select a value of the first one(ComboBoxCompany), i want that the second combobox(ComboBoxDatabase) chooses the "dbName"-Value from the first combobox "Database"-Value
i tried this, but it doesn't
private void cbxBranch_SelectedIndexChanged(object sender, EventArgs e)
{
cbxDatabase.SelectedItem = (cbxCompany.SelectedItem as ComboBoxCompany).Database;
}
by setting
(cbxCompany.SelectedItem as ComboBoxCompany).Database
You try to set the selected item to the database string which does not 'exist' because it seems you added a class as comboboxitem.
You need to set the SelectedItem to the real object. You could search for this by using linq (sample code):
var company = cbxCompany.SelectedItem as ComboBoxCompany;
if(company == null)
return;
var dbItem = _databaseComboBoxItems.FirstOrDefault(x=>x.CompanyName = company.CompanyName && x.Database == company.DatabaseName);
if(dbItem == null)
return;
cbxDatabase.SelectedItem = dbItem;

C# WinForms DataGridView ComboBox databinding

I believe I have read every document on the internet regarding this issue and I'm still having trouble.
I have a DataGridView populated by two List and combined into a var
topList = ShippingOrder.GetTopGroups();
topItemsList = ShippingOrder.GetCurrentTopSheet();
topList.AddRange(topItemsList);
var newList = topList.OrderBy(x => x.GroupOrder).ToList();
One of the columns in the DdataGridView is a ComboBox. It's populated from a separate List
alertList = GetComboBoxValue();
It's values are associated with the datagridview combox.
emailRecipientDataGridViewComboBoxColumn.DataSource = alertList;
emailRecipientDataGridViewComboBoxColumn.DataPropertyName = "EmailAlert";
emailRecipientDataGridViewComboBoxColumn.DisplayMember = "PopUpText";
emailRecipientDataGridViewComboBoxColumn.ValueMember = "PopUpValue";
The DataPropertyName corresponds to topList.EmailAlert.
The DisplayMember corresponds to alertList.PopUpText.
The ValueMember corresponds to alertList.PopUpValue.
Then the datagrid is filled
dgvTopSheet.DataSource = newList;
CurrencyManager cm = (CurrencyManager)(dgvTopSheet.BindingContext[newList]);
cm.Refresh();
Once the datagrid is filled, everything looks good except the combobox value is not showing. I can use the dropdown arrow and the values acquired from the alertList show up but the comboxbox value isn't binding the value from topList on load.
As I understand from the 50 plus documents I've read on the datagridviewcombobox the DataPropertName is the field needed to bind the control to the data in the dgv. This doesn't appear to be working and 4 hours later I'm a bit frustrated. Something simple seems to be alluding me greatly.
Any help is appreciated.
eta -
The BusinessObjects Class
public class BusinessObjects : INotifyPropertyChanged
{
public BusinessObjects()
{
}
private string popUpText;
public string PopUpText
{
get { return popUpText; }
set
{
popUpText = value;
OnPropertyChanged(new PropertyChangedEventArgs("PopUpText"));
}
}
private string popUpValue;
public string PopUpValue
{
get { return popUpValue; }
set
{
popUpValue = value;
OnPropertyChanged(new PropertyChangedEventArgs("PopUpValue"));
}
}
}
The ShippingOrder Class
public class ShippingOrder : INotifyPropertyChanged
{
private string emailAlert;
public string EmailAlert
{
get { return emailAlert; }
set
{
emailAlert = value;
OnPropertyChanged(new PropertyChangedEventArgs("EmailAlert"));
}
}
private string partNumber;
public string PartNumber
{
get { return partNumber; }
set
{
partNumber = value;
OnPropertyChanged(new PropertyChangedEventArgs("PartNumber"));
}
}
}
sample data looks like:
ShippingOrder.PartNumber = "1234Dp01".
ShippingOrder.EmailAlert = "BSmith#example.com".
BusinessObject.PopUpText = "Bob Smith".
BusinessObject.PopUpValue = "BSmith#example.com".

C# populate a combo box from a method

What I would like to do is to populate a drop down menu from a database.
First of all I plan to use a combo box.
I have created an object that contains the data that I need to take from the database. The object is as follows
namespace RLMD
{
public class FlashCardLevel
{
private int intFCLId;
private String strFCLName;
public FlashCardLevel(int intFCLId, String strFCLName)
{
this.intFCLId = intFCLId;
this.strFCLName = strFCLName;
}
public int IntFCLId
{
get { return intFCLId; }
set { this.intFCLId = value; }
}
public String StrFCLName
{
get { return strFCLName; }
set { this.strFCLName = value; }
}
}
}
What I need to do is to add a list of items from a database, but for ease of use I have simulated given some sample data.
public List<FlashCardLevel> Rifle(List<FlashCardLevel> fcLevel)
{
fcLevel.Add(new FlashCardLevel(1, "Severe"));
fcLevel.Add(new FlashCardLevel(2, "Moderate"));
fcLevel.Add(new FlashCardLevel(3, "Mild"));
fcLevel.Add(new FlashCardLevel(4, "Slight"));
return fcLevel;
}
I'm calling the method here.
List<FlashCardLevel> fcLevel = new List<FlashCardLevel>();
talkToDatabase.Rifle(fcLevel);
this.comboCardLevel.DataSource = fcLevel;
this.comboCardLevel.DisplayMember = "Name";
this.comboCardLevel.ValueMember = "Value";
The combobox is displaying no information.
I would appreciate any help
Updated:
The DisplayMember Property should be referring to FlashCardLevel (class), Property StrFCLName and ValueMember should be pointing to IntFCLId.
List<FlashCardLevel> fcLevel = new List<FlashCardLevel>();
talkToDatabase.Rifle(fcLevel);
this.comboCardLevel.DataSource = listFromDatabase;
this.comboCardLevel.DisplayMember = "StrFCLName";
this.comboCardLevel.ValueMember = "IntFCLId";
The DisplayMember and ValueMember should point to your properties name.
this.comboCardLevel.DisplayMember = "IntFCLId";
this.comboCardLevel.ValueMember = "StrFCLName";

How can I load data in combo item property when another changed, in propertygrid c#?

I have two property in my class: MyCountry & MyCity. I set this class to sourceobject of a property grid. I want load cities i combo when select a country. for example I have 2 Country data:
Country1
Country2
And For Country1, I have (city data)
City11
City12
City13
And For Country2, I have (city data)
city21
City22
City23
When I change select country item in propertygrid, I want load cities of it in city item. this mean, when select Country1, display City11,City12,City13 in City item and when select Country2 Display City21,Cityy22,City23 in City Item.
How can I It ?
my class is :
public class KeywordProperties
{
[TypeConverter(typeof(CountryLocationConvertor))]
public string MyCountry { get; set; }
[TypeConverter(typeof(CityLocationConvertor))]
public string MyCity { get; set; }
}
and I use below class for load countries data for display in combo :
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
HumanRoles Db = new HumanRoles();
List<LocationsFieldSet> Items = new List<LocationsFieldSet>();
Items = Db.LoadLocations(0);
string[] LocationItems = new string[Items.Count];
int count = 0;
foreach (LocationsFieldSet Item in Items)
{
LocationItems[count] = Item.Title;
count++;
}
return new StandardValuesCollection(LocationItems);
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
}
The ITypeDescriptorContext interface provides a property called Instance
which lets you access the object to which the type descriptor request is connected.
You can use this property to determine the current value of the MyCountry property
the user selected. Depending on the value you can load the cities for this country.
Furthermore, in the setter of the MyCountry property I check whether or not the
new value is different from the old one and if this is the case I reset the MyCity property
(to not get an invalid combination of country and city).
Here is a small code sample. For the sake of simplicity I only use one type converter
for both properties.
public class KeywordProperties
{
public KeywordProperties()
{
MyCountry = "Country1";
}
private string myCountry;
[TypeConverter(typeof(ObjectNameConverter))]
public string MyCountry
{
get { return myCountry; }
set
{
if (value != myCountry)
MyCity = "";
myCountry = value;
}
}
private string myCity;
[TypeConverter(typeof(ObjectNameConverter))]
public string MyCity
{
get { return myCity; }
set { myCity = value; }
}
}
public class ObjectNameConverter : StringConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
KeywordProperties myKeywordProps = context.Instance as KeywordProperties;
if (context.PropertyDescriptor.Name == "MyCountry")
{
List<string> listOfCountries = new List<string>();
listOfCountries.Add("Country1");
listOfCountries.Add("Country2");
return new StandardValuesCollection(listOfCountries);
}
List<string> listOfCities = new List<string>();
if (myKeywordProps.MyCountry == "Country1")
{
listOfCities.Add("City11");
listOfCities.Add("City12");
listOfCities.Add("City13");
}
else
{
listOfCities.Add("City21");
listOfCities.Add("City22");
listOfCities.Add("City23");
}
return new StandardValuesCollection(listOfCities);
}
}
In the example above there is one side effect I do not like.
Setting the MyCountry property leads to settting also the MyCity property.
To workaround this side effect you could also use the PropertyValueChanged event
of the PropertyGrid to handle invalid country/city selections.
private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
{
if (e.ChangedItem.Label == "MyCountry")
{
if(e.ChangedItem.Value != e.OldValue)
m.MyCity = "";
}
}
If you use this event, just repalce the code in the setter of the MyCountry property with:
myCountry = value;

Refreshing the listbox item after an element is changed

I have a ParameterItem class for adding some items to a listbox:
class ParameterItem
{
public string Name { get; set; }
public string Value { get; set; }
public ParameterItem(string name, string value)
{
Name = name;
Value = value;
}
public override string ToString()
{
return Name + " = " + Value;
}
public override bool Equals(object obj)
{
if (obj is ParameterItem)
return (Name == ((ParameterItem)obj).Name);
return false;
}
public override int GetHashCode()
{
return Name.ToLowerInvariant().GetHashCode();
}
}
And you can add items to the listbox using two textboxes (name and value). When you click on an item in the listbox, the textboxes get filled with the name and the value of the ParameterItem. I have the following code to change the contents of the selected ParameterItem in the listbox:
private void btnSaveParameter_Click(object sender, EventArgs e)
{
ParameterItem currentParameter = new ParameterItem(textParameterName.Text,
textParameterValue.Text);
// If we already have the parameter set then edit it.
if (lstbxSetParameters.Items.Contains(currentParameter))
{
((ParameterItem)lstbxSetParameters.SelectedItem).Value = currentParameter.Value;
lstbxSetParameters.;
}
// If it's not set yet then add it to the listbox.
else
{
lstbxSetParameters.Items.Add(currentParameter);
textParameterName.Text = String.Empty;
textParameterValue.Text = String.Empty;
}
}
The problem is, even though I can change the contents of the selected ParameterItem, in the listbox, it still looks like it is not changed.
For example I have a parameter in the list box:
TestParameter = 10
And I change the ParameterItem to
TestParameter = 5
but in the listbox it still looks like
TestParameter = 10
even though it's been changed.
How can I solve this problem? I think the listbox item should call the ToString() method of the ParameterItem again and refresh itself but how?
Or is there a better way to add key value pairs in the listbox?
You can change the selected item by remove it and insert it again.
// If we already have the parameter set then edit it.
if (lstbxSetParameters.Items.Contains(currentParameter))
{
var newItem = new ParameterItem((lstbxSetParameters.SelectedItem as ParameterItem).Name, currentParameter.Value);
var index = lstbxSetParameters.SelectedIndex;
lstbxSetParameters.Items.RemoveAt(index);
lstbxSetParameters.Items.Insert(index, newItem);
lstbxSetParameters.SelectedIndex = index;
}
My solution:
string[] nList = new string[lb.Items.Count];
nList = lb.Items.OfType<string>().ToArray();
nList[lb.SelectedIndex] = newValue;
lb.Items.Clear();
lb.Items.AddRange(nList);
This way instead of changing the selected item (with a lot of problem) I reloaded the Listbox with the item changed in the array.

Categories