I'm surprised I hadn't noticed this before, and couldn't find this question anywhere. Perhaps I'm missing something obvious. When I have the DataSource of a ComboBox set to a BindingList, and I remove an item from the list, the SelectedValueChanged or the SelectedIndexChanged events are not fired, but the SelectedValue does change. Here is the full source to reproduce:
public partial class Form1 : Form
{
public readonly BindingList<string> Items = new BindingList<string>();
public Form1()
{
InitializeComponent();
Items.Add("One");
Items.Add("Two");
Items.Add("Three");
comboBox1.DataSource = Items;
comboBox1.SelectedValueChanged += comboBox1_SelectedValueChanged;
comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;
button1.Click += button1_Click;
timer1.Interval = 250;
timer1.Tick += timer1_Tick;
timer1.Start();
}
private string GetCurrentText()
{
return comboBox1.SelectedValue as string ?? "NULL";
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
textBox1.Text += "Index Changed: " + GetCurrentText() + Environment.NewLine;
}
private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
textBox1.Text += "Value Changed: " + GetCurrentText() + Environment.NewLine;
}
private void timer1_Tick(object sender, EventArgs e)
{
Text = GetCurrentText();
}
private void button1_Click(object sender, EventArgs e)
{
Items.Remove((string)comboBox1.SelectedValue);
}
}
All the form has is a ComboBox, a Button, a Timer to keep track of the actual ComboBox's SelectedValue and a multiline TextBox to log the events.
To reproduce, run the form, select the second value ("Two") from the combo box and then press the button. No SelectedValueChanged nor SelectedIndexChanged event will be fired at the button press, but the form's text will show the new value ("Three") given by the timer, which will also be the value shown at the combo box. So the actual selected value will have certainly changed, with no event fired.
Unfortunately there's no SelectedItemChanged event so I don't know how are developers supposed to handle this situation. I'm not sure which other "edge" cases will cause the value to change silently so whatever hacky solution I come up with may not cover every case. I wonder if anyone has came up with a real solution.
This is logically true. After you choose 'Two' ,comboBox1.SelectedIndex = 1. Then you deleted 'Two' item. So 'Three' becomes index '1' from '2', no index changed occur in combo box. No combo's event will fire.
Your second time clicking button will fire combo's events.
Related
I wanted to focus to a TextBox when I leave an other TextBox.
Let's say I have 3 textboxes. The focus is in the first one, and when I click into the second one, I want to put the focus into the last one instead.
I subscribed to the first textbox's Leave event and tried to focus to the third textbox like: third.Focus(). It gains focus for a moment but then the second one got it eventually (the one I clicked).
Strangely if I replace the second TextBox to a MaskedTextBox (or to any other control), the focus remains on the third one.
Pressing Tab does work though.
These are plain textboxes right from the toolbox.
What is the reason, how can I solve this?
Try to handle Enter event of the textBox2. (In properties window double click on Enter event)
//From Form1.Designer.cs
this.textBox2.Enter += new System.EventHandler(this.textBox2_Enter);
private void textBox2_Enter(object sender, EventArgs e)
{
textBox3.Focus();
}
EDIT:
This code looks very strange, but it works for me. According to this post HERE I use ActiveControl property instead of Focus() method. But behavior of TextBox is very strange because it try to be focused multiple times.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
foreach (Control control in Controls)
{
control.LostFocus += (s, e) => Console.WriteLine(control.Name + " LostFocus");
control.GotFocus += (s, e) =>
{
Console.WriteLine(control.Name + " GotFocus");
if (!requestedFocusToTextBox2) return;
ActiveControl = textBox2; //textBox2.Focus() doesn't work
requestedFocusToTextBox2 = false;
};
}
}
private bool requestedFocusToTextBox2;
private void textBox1_Leave(object sender, EventArgs e)
{
ActiveControl = textBox2;
requestedFocusToTextBox2 = true;
}
}
So I was thinking about "if" statement to make it work, but I don't really understand how to connect it to "checked event". I am a beginner so please don't be rough on me
By default, radiobuttons are in a same group. So we can let their CheckedChanged event subscribe to a same method.
public Form1()
{
InitializeComponent();
radioButton1.CheckedChanged += radioButton_CheckedChanged;
radioButton2.CheckedChanged += radioButton_CheckedChanged;
radioButton3.CheckedChanged += radioButton_CheckedChanged;
}
Then use the parameter sender to get the selected radiobutton.
private void radioButton_CheckedChanged(object sender, EventArgs e)
{
// Clear listbox
listBox1.Items.Clear();
// Add the selected radiobutton into listbox
listBox1.Items.Add(((RadioButton)sender).Text);
}
The test result,
I want to know how to output to a TextBox as soon as a user has clicked on a series of RadioButtons and clicked the CheckBox(es) which are found inside various GroupBoxes on the Form.
Any help will be really appreciated, in case this question has already been answered in the past let me know I have search for it but could not find anything like this.
Sample Form layout:
I am no good at chasing the pictures and especially code as picture doesn't help anyone. Anyway next time please don't do that.
First, for all of your radio and checkboxes (radChocolate, radVanilla, ... radSmall, ..., chkChocoChips, ...) double click and fill Checked event such as:
private void radChocolate_CheckedChanged(object sender, EventArgs e)
{
CalculatePrice();
}
private void radVanilla_CheckedChanged(object sender, EventArgs e)
{
CalculatePrice();
}
// Do the same for other radio and checkboxes
Then add the CalculatePrice code as such (prices are arbitrary):
private void CalculatePrice()
{
decimal price = 0M;
if (radChocolate.Checked) price += 75M;
if (radVanilla.Checked) price += 65M;
if (radStrawberry.Checked) price += 55M;
if (radSmall.Checked) price += 20M;
if (radLarge.Checked) price += 30M;
if (chkChocoChips.Checked) price += 5M;
if (chkCookieCandy.Checked) price += 4M;
if (chkNuts.Checked) price += 3M;
if (chkFreshFruits.Checked) price += 2M;
txtPrice.Text = price.ToString("C");
}
This would do what you wanted to.
You either need to create an event handler for each radio button, or create a single event handler for all the radio buttons. It would depend on what you are trying to accomplish. For the radio button you would want to subscribe to the CheckedChanged event. Then inside this event you can change the text box.
private void radioButtonChangeText_CheckedChanged(object sender, EventArgs e)
{
//Code here to change text box or call sub
textBox.Text = "Hello world";
}
Based upon your link, you can create one event handler and bind it to all the events. (Link explaining binding)
So, every time any value is changed in your form, only one function gets called.
Then, check the values of every component present in your form and calculate value of your textbox.
Right click on a radio button and the go to properties, there click on "events" (that lightning sign). There is an event there called "CheckedChanged". Double click on the cell next to it to generate the event method.
it will generate a code like this,
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
MessageBox.Show("hi there");
}
you should be able to put any thing you want in there. Assuming you want to show hide the TextBox, you can do it in there.
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
setCheckBoxValue();
}
private void radioButton2_CheckedChanged(object sender, EventArgs e)
{
setCheckBoxValue();
}
private void setCheckBoxValue()
{
int finalPrice = 0;
if (radioButton1.Checked == true)
{
finalPrice = finalPrice + 75;
}
else if (radioButton2.Checked == true)
{
finalPrice = finalPrice + 87;
}
textBox1.Text = finalPrice.ToString("C");
}
I am still learning how to do with event handler. What I want is: When I click the txtMonday to get focused, then I click the remove button to clear this selected textbox. Problem is: when I click the remove button for the selected textbox, all the unselected textboxes are clear. I only want to remove the selected textbox. How to solve this problem? Your code example much appreciated. Thanks! I am using WPF and C#.
private void btnRemoveClick(object sender, RoutedEventArgs e)
{
TextBox text = new TextBox();
text.GotFocus += new RoutedEventHandler(txtMonday_GotFocus);
txtMonday.Clear();
text.GotFocus += new RoutedEventHandler(txtTuesday_GotFocus);
txtTuesday.Clear();
}
private void txtMonday_GotFocus(object sender, RoutedEventArgs e)
{
}
private void txtTuesday_GotFocus(object sender, RoutedEventArgs e)
{
}
This should do what you want. I suggest you do some more studying about C# though, as your code shows some fundamental misunderstandings.
//you'll need a variable to store the last focused textbox.
TextBox txtLast;
public MainWindow()
{
InitializeComponent();
//add an event for all the textboxes so that you can track when one of them gets focus.
txtSunday.GotFocus += txt_GotFocus;
txtMonday.GotFocus += txt_GotFocus;
txtTuesday.GotFocus += txt_GotFocus;
txtWednesday.GotFocus += txt_GotFocus;
txtThursday.GotFocus += txt_GotFocus;
txtFriday.GotFocus += txt_GotFocus;
txtSaturday.GotFocus += txt_GotFocus;
//default to clearing sunday to avoid exception
//you could also let it clear a new TextBox(), but this is wasteful. Ideally,
//you would handle this case gracefully with an if statement, but I will leave that
//as an exercise to the reader.
txtLast = txtSunday;
}
private void txt_GotFocus(object sender, RoutedEventArgs e)
{
//whenever you click a textbox, this event gets called.
//e.source is the textbox, but since it is is just an "Object" we need to cast it to a TextBox
txtLast = e.Source as TextBox;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//this will clear the textbox which last had focus. If you click a button, the current textbox loses focus.
txtLast.Clear();
}
I want to handle the event when a value is changed in a ComboBox in a DataGridView cell.
There's the CellValueChanged event, but that one doesn't fire until I click somewhere else inside the DataGridView.
A simple ComboBox SelectedValueChanged does fire immediately after a new value is selected.
How can I add a listener to the combobox that's inside the cell?
The above answer led me down the primrose path for awhile. It does not work as it causes multiple events to fire and just keeps adding events. The problem is that the above catches the DataGridViewEditingControlShowingEvent and it does not catch the value changed. So it will fire every time you focus then leave the combobox whether it has changed or not.
The last answer about CurrentCellDirtyStateChanged is the right way to go. I hope this helps someone avoid going down a rabbit hole.
Here is some code:
// Add the events to listen for
dataGridView1.CellValueChanged += new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);
dataGridView1.CurrentCellDirtyStateChanged += new EventHandler(dataGridView1_CurrentCellDirtyStateChanged);
// This event handler manually raises the CellValueChanged event
// by calling the CommitEdit method.
void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dataGridView1.IsCurrentCellDirty)
{
// This fires the cell value changed handler below
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// My combobox column is the second one so I hard coded a 1, flavor to taste
DataGridViewComboBoxCell cb = (DataGridViewComboBoxCell)dataGridView1.Rows[e.RowIndex].Cells[1];
if (cb.Value != null)
{
// do stuff
dataGridView1.Invalidate();
}
}
You can also handle the CurrentCellDirtyStateChanged event which gets called whenever a value is changed, even if it's not commited. To get the selected value in the list, you would do something like:
var newValue = dataGridView.CurrentCell.EditedFormattedValue;
This is the code, which will fire the event of the selection in the comboBox in the dataGridView:
public Form1()
{
InitializeComponent();
DataGridViewComboBoxColumn cmbcolumn = new DataGridViewComboBoxColumn();
cmbcolumn.Name = "cmbColumn";
cmbcolumn.HeaderText = "combobox column";
cmbcolumn.Items.AddRange(new string[] { "aa", "ac", "aacc" });
dataGridView1.Columns.Add(cmbcolumn);
dataGridView1.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(dataGridView1_EditingControlShowing);
}
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
ComboBox combo = e.Control as ComboBox;
if (combo != null)
{
combo.SelectedIndexChanged -= new EventHandler(ComboBox_SelectedIndexChanged);
combo.SelectedIndexChanged += new EventHandler(ComboBox_SelectedIndexChanged);
}
}
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
string item = cb.Text;
if (item != null)
MessageBox.Show(item);
}
I have implemented another solution, that seems more responsive (e.g.. quicker and less clicks) than Mitja Bonca's above. Although sometimes the combobox closes to quickly. This uses the CurrentCellDirtyStateChanged and CellMouseDown callback
private void myGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (myGrid.CurrentCell is DataGridViewComboBoxCell)
{
myGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);
myGrid.EndEdit();
}
}
private void myGrid_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (myGrid.Rows[e.RowIndex].Cells[e.ColumnIndex] is DataGridViewComboBoxCell)
{
myGrid.CurrentCell = myGrid.Rows[e.RowIndex].Cells[e.ColumnIndex];
myGrid.BeginEdit(true);
((ComboBox)myGrid.EditingControl).DroppedDown = true; // Tell combobox to expand
}
}
ComboBox cmbBox = (ComboBox)sender;
MessageBox.Show(cmbBox.SelectedValue.ToString());