I have a basic form with a combobox, a textbox, and a button on it. The combobox has an unalterable number of items within it, but the items themselves can be changed by inputting a new value for the selected item.
From the example in the picture, if I input a string such as "identifier", the selected item in the combobox changes from "ID" to "identifier", as expected. However, if I input "id", the logic (below) executes normally, the item updates, but visually, the item does not change from "ID" to "id".
Here is the code for the event handler of the button
private void btnApply_Click(object sender, EventArgs e) {
string newValue = txtNewName.Text;
if(string.IsNullOrWhiteSpace(newValue)) {
MessageBox.Show("Please input a new column name");
return;
}
if(cmbHeaderNames.Items.Contains(newValue)) {
MessageBox.Show("A column with that name already exists");
return;
}
cmbHeaderNames.Items[cmbHeaderNames.SelectedIndex] = newValue;
txtNewName.Text = "";
}
I believe that the ComboBox is doing some string comparison, because the following code sample works.
if (comboBox1.SelectedItem.ToString().ToUpper() == textBox1.Text.ToUpper())
{
comboBox1.Items[comboBox1.SelectedIndex] = string.Empty;
comboBox1.Items[comboBox1.SelectedIndex] = textBox1.Text;
}
Apparently, the update successfully applies if the two string values are not identical when applying ToUpper() or ToLower().
Related
I am trying to make a datagridview in which there exists a combobox column, and this column is binded a list of options. My logic is that, if the user selects the wrong option, the program could detect and deselect this wrong option(which means comboboxCell.value = null).
The psuedo code for this logic is as follows:
//use CurrentCellDirtyStateChanged and CellValueChanged as event listeners
this.DGV.CurrentCellDirtyStateChanged += DGV_CurrentCellDirtyStateChanged;
this.DGV.CellValueChanged += DGV_CellValueChanged;
//CurrentCellDirtyStateChanged event
private void DGV_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (DGV.IsCurrentCellDirty)
{
DGV.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
//CellValueChanged event
private void DGV_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (!CheckingCorrect(DGV.CurrentCell))
{
// set selected value null
DGV.CurrentCell.Value = null
}
}
However, after the code sets currentcell value to null, the datagridview cell still kept the selected value shown.
I also tried may other ways like DGV.ClearSelection(), but none of these works.
There are two things that will make working with the DataGridViewComboBoxColumn/Cell easier...
Make a Class specifically for the combo box column
Use the proper event to help in casting the DataGridViewComboBoxCell to a
regular ComboBox.
In this example I made a simple Class called ComboValues that has two properties for the column ValueMember and DisplayMember. In this example the ValueMember is an int, however you could leave it out or use some other type that fits your needs. This class will simplify things as we will have the properties for both the ValueMember and DisplayMember for the combo box column.
This ComboValues Class may look something like…
public class ComboValues {
public int Value { get; set; }
public string Display { get; set; }
}
Then a method to get a List<ComboValues> from the DB that we will use as a DataSource for the combo box column.
private List<ComboValues> GetComboValues() {
List<ComboValues> items = new List<ComboValues>();
items.Add(new ComboValues { Value = 0, Display = null });
items.Add(new ComboValues { Value = 1, Display = "Option 1" });
items.Add(new ComboValues { Value = 2, Display = "Option 2" });
items.Add(new ComboValues { Value = 3, Display = "Option 3" });
items.Add(new ComboValues { Value = 4, Display = "Option 4" });
return items;
}
And setting up the combo box column for the grid…
private DataGridViewComboBoxColumn GetComboCol() {
DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
col.HeaderText = "Combo Items";
col.ValueMember = "Value";
col.DisplayMember = "Display";
col.DataSource = GetComboValues();
return col;
}
We will call the above method in the forms Load event to add the column to the Grid…
private void Form1_Load(object sender, EventArgs e) {
DGV.Columns.Add(GetComboCol());
}
Next, we want to set up the edited DataGridViewComboBoxCell to act like a REGULAR ComboBox. We can do this using the grids EditingControlShowing event. This event will fire when the user clicks into a cell and in this case if the user clicks into a combo box cell, then we want to cast that cell to a globally defined ComboBox. So, we will need a global ComboBox variable called something like… EditedComboBox.
ComboBox EditedComboBox = null;
Is what we will do is that when the grids EditingControlShowing event fires and we check to see if it is the combo box cell, then we simply cast that cell to our global EditedComboBox and wire up its SelectedIndexChanged event. Then we can capture “when” the user “changes” a value in the combo box cell. The EditingControlShowing event may look something like…
private void DGV_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
if (DGV.CurrentCell.ColumnIndex == 0) {
EditedComboBox = (ComboBox)e.Control;
if (EditedComboBox != null) {
EditedComboBox.SelectedIndexChanged += new EventHandler(ComboBox_SelectedIndexChanged);
}
}
}
Above, column index 0 is the target combo box column. All we need to do is implement and wire up the SelectedIndexChanged event and wait for the user to change the combo box value.
When the user does indeed change the combo boxes value, then our SelectedIndexChanged event will fire and it is in this event where you would “CHECK” if the selected value needs adjustments on some parameters. In this example, the condition is if the user selects “Option 3”, then that is an invalid value and we will set the cells value to null. This event may look something like…
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e) {
//Debug.WriteLine("CB_SelectedIndexChanged");
if (EditedComboBox != null) {
ComboValues cv = (ComboValues)EditedComboBox.SelectedItem;
if (cv != null && !CheckingCorrect(cv.Display)) {
EditedComboBox.SelectedIndexChanged -= new EventHandler(ComboBox_SelectedIndexChanged);
EditedComboBox.SelectedIndex = 0;
EditedComboBox.SelectedIndexChanged += new EventHandler(ComboBox_SelectedIndexChanged);//DGV.CurrentCell.Value = 0;
}
}
}
In this event, we grab (cast) the combo boxes SelectedItem to a ComboValues object. With it we can easily check what value is selected and in turn set its value to null if needed. Note “item” 0 in our List<ComboValues> is the null value, so we set the combo boxes SelectedIndex to zero (0) to make the grid display a null value.
Also, since we are “changing” the combo boxes Index, we do NOT want this event to re-fire.
Lastly, we need one more event to wire up to TURN OFF the SelectedIndex changed event to prevent it from firing more than we want. In this case we will wire up the grids CellLeave event. In that event, the user is leaving the cell and if the EditedComboBox is not null... then we know we need to un-wire the event. It may look something like…
private void DGV_CellLeave(object sender, DataGridViewCellEventArgs e) {
if (EditedComboBox != null) {
EditedComboBox.SelectedIndexChanged -= new EventHandler(ComboBox_SelectedIndexChanged);
EditedComboBox = null;
}
}
I altered the checking code to check for a string and not necessarily a cell. The condition checker code…
private bool CheckingCorrect(string cellValue) {
if (cellValue != null && cellValue == "Option 3") {
return false;
}
else {
return true;
}
}
I hope this helps and makes sense. If you have questions, then feel free to ask.
How can I get data from DataGrid when ComboBox' text is equal with the record of the DataGrid:
combobox1.ItemsSource = database.Mahs.ToList();
combobox1.DisplayMemberPath = "MahName";
and
private void datagrid_customer_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var data = datagrid_customer.SelectedItem;
string id = (datagrid_customer.SelectedCells[0].Column.GetCellContent(data) as TextBlock).Text;
txt_f1.Text = id;
}
It shows me the id, but when i selected item but i want show me id when combobox.Text = name of the row in the DataGrid, then show the id of that row.
I would suggest changing your approach slightly, and retrieving the entire object from both controls for the comparison. This way you have full access to the properties of each selected object.
If the objects you're retrieving from your database override .Equals and .GetHashCode you could do away with some of the if statements below. But to get you started here's a quick example of your change listener
private void datagrid_customer_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Cast the objects from your DataGrid and your ComboBox.
YourDataObject dataItem = (YourDataObject)dataGrid1.SelectedItem;
YourDataObject comboItem = (YourDataObject)combo.SelectedItem;
// Compare your objects and decide if they're the same. Ideally you would
// have Equals and HashCode overridden so you could improve this
if (dataItem == null || comboItem == null)
text.Text = "Not Matching";
else
{
if (dataItem.MahName == comboItem.MahName)
// You've got full access to the object and all it's properties
text.Text = dataItem.Id.ToString();
else
text.Text = "Not Matching";
}
}
I have a combo box witch is DropDownList and i bind it to a property of a class. this Combo Box is populated with an array.
now in run time when i change selected item by mouse click every things sounds good. but when change item by arrow key any thing wont work. even textchanged event of combo box would not raise.
For ComboBoxit's really easy to use selected index changed event, instead of text changed event. It will fire by mouse or keyboard, when it changes the selection item of a ComboBox.
Example:
private void CB_Company_SelectedIndexChanged(object sender, EventArgs e)
{
if (CB_Company.SelectedItem.ToString() != "Select a company" & CB_Company.SelectedItem.ToString() != "")
{
CB_Company.BackColor = Color.White;
CB_Company.Enabled = false;
RB_Option1.Enabled = true;
RB_Option2.Enabled = true;
}
}
Populating combobox method:
private void SetDropDownItems()
{
List<DropDownModel> dropDownModel = new List<DropDownModel>();
dropDownModel.Add(new DropDownModel()
{
Name = "Select a company",
Value = ""
});
dropDownModel.Add(new DropDownModel()
{
Name = "My Company",
Value = "Comp"
});
CB_Company.DataSource = dropDownModel;
CB_Company.DisplayMember = "Name";
CB_Company.ValueMember = "Value";
}
I hope you get the idea.
I have a listview and this listview will be updated when a message is coming in.
The code below is about how I get the selected row's value.
private void CallTabLv_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string callDetailValue = "";
dynamic selectedCallDetail;
//When a row of call detail is selected, return the selected row's value only
if (LineBtn1.IsChecked == true)
{
selectedCallDetail = CallTabLv1.SelectedItem;
callDetailValue = selectedCallDetail.Value;
}
if (LineBtn2.IsChecked == true)
{
selectedCallDetail = CallTabLv2.SelectedItem;
callDetailValue = selectedCallDetail.Value;
}
if (string.IsNullOrEmpty(callDetailValue))
callDetailValue = string.Empty;
Clipboard.Clear();
Clipboard.SetText(callDetailValue);
}
It worked fine for first coming message and I could get the selected row's value. The problem is when second message came in, my application stopped and returned "Cannot perform runtime binding on a null reference".
By the way, to return single selected row' value, which one should be used: CallTabLv1.SelectedItem or CallTabLv1.SelectedItems[0]? As I tried, if the latter is used, it will return "ArgumentOutOfRange Exception" when second message is coming in.
Please help.
Update:
When the message is coming in, I update the listview by clearing the whole listview and then print it line by line. I'm not sure if it is caused by the way I update the listview.
So this is probably happening because you are clearing the collection in which you have now changed the selected item. Since the item can be null at that time the dynamic object will be unable to access the property "Value"
You are checking if a checkbox is checked which is not necessarily a condition of if the selected item will exist. I would suggest your code be updated as such.
private void CallTabLv_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string callDetailValue = "";
dynamic selectedCallDetail;
//When a row of call detail is selected, return the selected row's value only
if (LineBtn1.IsChecked == true)
{
selectedCallDetail = CallTabLv1.SelectedItem;
}
if (LineBtn2.IsChecked == true)
{
selectedCallDetail = CallTabLv2.SelectedItem;
}
// I think the 'invalid' casting is happening with the "selectedCallDetail.Value" as when you clear a listbox it is no longer selected.
callDetailValue = (selectedCallDetail != null) ? selectedCallDetail.Value : string.Empty;
Clipboard.Clear();
Clipboard.SetText(callDetailValue);
}
You should be using the SelectedItem as the SelectedItems collection may be null or empty, If you only ever want one result this is usually the best. also make sure your ListBox only allows for a single item to be selected so that the user cannot crash your code by selecting multiple items using SHIFT or CTRL click
Simple problem: I am checking to see if a combobox has had an item selected with string.IsNullOrEmpty(). Problem is, even if is is selected, the error message appears. What am I doing wrong?
Here is my code:
private void button1Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(comboBox1.SelectedText))//here should skip to else - but doesn't
{
MessageBox.Show("You must select a conversion type", "Error");
}
else
{
if (comboBox1.SelectedText == "Currency")
{
double input = Convert.ToDouble(textBox1.Text);
if (!string.IsNullOrEmpty(comboBox2.SelectedText))
{
string type = comboBox2.SelectedText;
double result = convertCurrency(type, input);
if (result != -1)
{
label1.Text = Convert.ToString(result);
}
}
else
{
MessageBox.Show("You must select a conversion type", "Error");
}
}
else
{
MessageBox.Show("curency");
}
}
}
Note: This is my second ever C# program - so please don't yell at me if I'm being stupid.
Generally a few observations/suggestions.
First you're using string values and are basing logic on these values, you might want to look into using an Enum and binding all it's values to the combo box. Then use the SelectedItem property and compare it to the Enum.
When nothing is selected the SelectedItem will return NULL, another option is using SelectedIndex which will return -1 when no item has been selected.
So with the SelectedIndex it would become something like;
if (comboBox1.SelectedIndex == -1)//Nothing selected
{
MessageBox.Show("You must select a conversion type", "Error");
}
else
{
//Do Magic
}
Generally using string comparisons should only be done when anything "strong" like an int comparison or even better an enum comparison is not possible. (Maybe it's just me though but strings change to often and are just scary for this sort of stuff.)
For the enum suggestion possibly look at one of these links;
Binding an enum to a WinForms combo box, and then setting it
Load values of enum type into a combobox
Is it possible to load items from an Enum to a ComboBox in .NET 3.5?
Binding a ComboBox to an Enumeration
I'm not sure which .NET version and things you're using as binding is alot easier in WPF then in the old windows form (in my opinion).
from the MSDN doc, this answers your question exactly
You can use the SelectedText property to retrieve or change the
currently selected text in a ComboBox control. However, you should be
aware that the selection can change automatically because of user
interaction. For example, if you retrieve the SelectedText value in a
button Click event handler, the value will be an empty string. This is
because the selection is automatically cleared when the input focus
moves from the combo box to the button.
private void button2_Click(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex==-1)
{
MessageBox.Show("You must select a conversion type", "Error");
}
else
{
MessageBox.Show("Selected");
}
}
Another solution:
You can check whether the combobox has had an item selected by checking a condition with an Index which is out of range (which item is impossible to have), then, if it is not having a possible value, you can set it manually.
if (comboBox1.SelectedIndex == -1) //index out of range
{
//show the error message
comboBox1.SelectedIndex = 1; //set the first value to the combo box
}
else
{
//continue
}
Poor naming on microsoft's part. You should use comboBox.Text to get what you are looking for.
comboBox.SelectedIndex the index of the selected value
comboBox.SelectedItem if you using a DataSource, this is the item seleted in the datasource
comboBox.SelectedValuethe ValueMember of the Datasource or the currently selected value if you added your own Items
comboBox.Text The text that you see, even if it is not in the list
.SelectedText, refers to and text selected (highlighted) within the .Text
private void Resetbtn_Click(object sender, EventArgs e)
{
comboBox1.Items.Clear();
//Student is a combobox elements.Add again.
comboBox1.Items.Add("Student");
comboBox1.Items.Add("Staff");
}