set ComboBox selected item when another combobox changes the selected value c# - 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;

Related

Can't programmatically set a ComboBox selection

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.

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.

Comparing two object state,before and after update

first things first.
I have the following classes:
class Employee
{
private int employeeID;
private string firstName;
private string lastName;
private bool eligibleOT;
private int positionID;
private string positionName;
private ArrayList arrPhone;
public IList<Sector> ArrSector {get; private set;}
//the constructor method takes in all the information of the employee
public Employee(int empID, string fname, string lname, bool elOT, int pos, string posname)
{
employeeID = empID;
firstName = fname;
lastName = lname;
eligibleOT = elOT;
positionID = pos;
positionName = posname;
arrPhone = new ArrayList();
ArrSector = new List<Sector>();
}
//the constructor method takes in the employee id, the first name and the last name of the employee
public Employee(int empid, string firstname,string lastname)
{
employeeID = empid;
firstName = firstname;
lastName = lastname;
}
//overtides the first name and the last name as a string.
public override string ToString()
{
return firstName +" "+lastName;
}
public int EmployeeID
{
get { return employeeID; }
set { employeeID = value; }
}
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
public bool EligibleOT
{
get { return eligibleOT; }
set { eligibleOT = value; }
}
public int PositionID
{
get { return positionID; }
set { positionID = value; }
}
public string PositionName
{
get { return positionName; }
set { positionName = value; }
}
public ArrayList ArrPhone
{
get { return arrPhone; }
set { arrPhone = value; }
}
// The function assigns all the variables associated to the employee to a new object.
public static object DeepClone(object obj)
{
object objResult = null;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Position = 0;
objResult = bf.Deserialize(ms);
}
return objResult;
}
//Memento pattern is used to save the employee state.
//The changes will be rolled back if the update button not clicked
public class Memento : IMemento
{
private Employee originator = null;
private int employeeID;
private string firstName;
private string lastName;
private bool eligibleOT;
private int positionID;
private string positionName;
private ArrayList arrPhone;
private IList<Sector> arrSector;
public Memento(Employee data)
{
this.employeeID = data.EmployeeID;
this.firstName = data.FirstName;
this.lastName = data.LastName;
this.eligibleOT = data.EligibleOT;
this.positionID = data.PositionID;
this.positionName = data.PositionName;
this.arrPhone = data.ArrPhone;
this.originator = data;
this.arrSector = Extensions.Clone<Sector>(data.ArrSector);
}
}
I am using C sharp in winforms. the front end of my application has a listbox on the left end side which has the first name of the employee.on the left hand side, there are different textboxes which correspond to the employee selected in the list box. I have coded it in such a way that everytime i select an employee, its attributes, like the employee id, name, position, etc are displayed in these fields.
if the user changes any attribute of the employee, he has to click an update button to make the changes to the database.
now the real problem, when the user changes any field of the selected employee, and selects another employee without clicking the update button, i want to show a pop up box to tell the user that if he selects another employee , all the changes will be lost.
for this reason i have created the momento class to hold the previous state of the employee.
i have also tried overloading the == operator
public static bool operator ==(Employee e, Memento m)
{
return ((e.employeeID == m.employeeID) &&
(e.firstName == m.firstName) &&
e.lastName == m.lastName &&
e.eligibleOT == m.eligibleOT &&
e.positionID == m.positionID &&
e.positionName == m.positionName &&
e.arrPhone == m.arrPhone &&
e.ArrSector == m.arrSector);
}
public static bool operator !=(Employee e, Memento m)
{
return (e.employeeID != m.employeeID);
}
my idea was to compare the two object...
but m not successfull. how do i do it??how do i show the popup if changes are made.?where do i place the code to show the popup?
One word of warning...it's generally not a good idea to have different logic in your == and != operators. It's somewhat unintuitive to be able to have both == and != be false at the same time.
if(!(a == b) && !(a != b))
{
// head explodes
}
That aside, I'm guessing that you have your Employee class referenced as an object (or other parent class) in your comparison code. Maybe something like this:
if(listBox1.SelectedItem != currentMemento)
{
...
}
If this is the case, then the compiler isn't binding the != to your custom implementation. Cast listBox1.SelectedItem to Employee in order to force that.
if((Employee)listBox1.SelectedItem != currentMemento)
{
...
}
There are, however, many other approaches that you could take to solve this issue:
Make the implementation entirely on the GUI side, with a bool that gets set to true when the data in the text fields changes, then check that flag when changing employees
Implement the IComparable or IEquatable interfaces
Override the Equals method on the Employee and/or Memento class
(If you go with the second option, it's generally recommended that you complete the third as well)
Example
Here's an example of what you could do (I'm assuming you have a ListBox named listBox1 and you've attached to the SelectedIndexChanged event with the listBox1_SelectedIndexChanged function):
private Employee lastSelectedEmployee;
private Memento selectedMemento;
void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Employee selectedEmployee = (Employee)listBox1.SelectedItem;
if(lastSelectedEmployee != null && lastSelectedEmployee != selectedEmployee)
{
if(/*changes exist*/)
{
if(/*cancel changes*/)
{
listBox1.SelectedItem = lastSelectedEmployee;
return;
}
}
}
lastSelectedEmployee = selectedEmployee;
selectedMemento = //create the memento based on selectedEmployee;
}
You'll have to provide your own logic for the areas I've left comments, but the idea should be pretty straightforward.
Have a look at the IComparable interface. It requires you to implement the method you need t make such a comparison. KB article, Hopefully it turn English for you, on my PC it turns always German.
-sa

Can't alter DisplayMember in WinForms ComboBox

I'm trying to alter how a combobox is displayed using the following code:
private void UpdateMapRoadPointList(List<GeographicAddress> plstMapRoadPointList)
{
cboFind.DataSource = plstMapRoadPointList;
cboFind.DisplayMember = "ShortCode";
cboFind.ValueMember = "";
}
GeographicAddress is a class which has a ShortCode property which returns a string:
internal string ShortCode
{
get { return Distance + Carriageway; }
}
However, when using the application, the disaplyed value is still coming from GeographicAddress.ToString(). On debugging, it seems that cboFind.DisplayMember = "ShortCode" is having no effect! DisplayMember is "" before and after executing that line!
What am I missing?
public string ShortCode
{
get { return Distance + Carriageway; }
}
private void UpdateMapRoadPointList(List<GeographicAddress> plstMapRoadPointList)
{
cboFind.DataSource = plstMapRoadPointList;
cboFind.DisplayMember = "ShortCode";
}
this should work
Set ShortCode property to Public or it will fail and use GeographicAddress.ToString()

Categories