Modifying ComboBox SelectedIndex Without Triggering Event in C# - c#

My C# application has a comboBox with a SelectedIndexChanged event. Usually, I want this event to fire, but but sometimes I need the event to not fire. My comboBox is an MRU file list. If a file in the list is found to not exist, the item is removed from the comboBox, and the comboBox SelectedIndex is set to zero. However, setting the comboBox SelectedIndex to zero causes the SelectedIndexChanged event to fire, which in this case is problematic because it causes some UIF code to be run in the event handler. Is there a graceful way to disable/enable events for C# form controls? Thanks.

Start the eventhandler method with
ComboBox combo = sender as ComboBox;
if (combo.SelectedIndex == 0)
{
return;
}
If you're issue is with a different eventhandler you could remove the eventhandler's event registration first.
combo.SelectedIndexChanged -= EventHandler<SelectedIndexChangedEventArgs> SomeEventHandler;
combo.SelectedIndex = 0;
combo.SelectedIndexChanged += EventHandler<SelectedIndexChangedEventArgs> SomeEventHandler;

I have encountered this many times over the years. My solution is to have a class level variable called _noise and if I know I am about to change the index of combo or any other similiar control that fires when the selected index changes, I do the following in code.
private bool _noise;
Here is the code for the control event handler
private void cbTest_SelectedIndexChange(object sender, EventArgs e)
{
if (_noise) return;
// process the events code
...
}
Then when I know I am going to change the index, I do the following:
_noise = true; // cause the handler to ignore the noise...
cbTest.Index = value;
_noise = false; // let the event process again

I'm surprised there isn't a better way of doing this, but this is the way I do it. I actually use the Tag field of most controls so I don't have to subclass the control. And I use true/null as the values, since null is the default.
Of course, if you are actually using Tag, you'll need to do it differently...
In handler:
private void control_Event(object sender, EventArgs e)
{
if (control.Tag != null ) return;
// process the events code
...
}
In main code
try
{
control.Tag = true;
// set the control property
control.Value = xxx;
or
control.Index = xxx;
or
control.Checked = xxx;
...
}
finally
{
control.Tag = null;
}

One (fairly ugly) way would be to set a flag in the code that deletes the entry and then check that in the SelectedIndexChanged handler:
if (!deletedEntry)
{
// Do stuff
}
deletedEntry = false;
A better way might be to remove your SelectedIndexChanged event handler at the start of the delete method and reinstate it at the end. This way you code won't know the index has changed.

There's a better way!
combo_box = QComboBox() # your combobox
combo_box.blockSignals(True)
combo_box.setCurrentIndex(self, ix)
combo_box.blockSignals(False)

Related

Is it possible to fire EditValueChanged event in CheckedComboBoxEdit control immediately after the item has been checked

I need to update the edit value of the CheckedComboBoxEdit control immediately after the item has been checked
The MouseUp event can be used to trigger EndEditwhich will commit the change slightly faster.
I used this to solve my simular issue when working with a CheckBox within a DateGridView. As by default the event to submit changes in a DataGridView only fires when leaving the cell.
You should subscribe Popup event of CheckedComboBoxEdit, find CheckedListBoxControl and subscribe ItemCheck event. Like this:
void _orgStructEntitesCheckedComboBoxEdit_Popup(object sender, EventArgs e)
{
var popup = (IPopupControl)sender;
var control = popup.PopupWindow.Controls.OfType<PopupContainerControl>().First().Controls.OfType<CheckedListBoxControl>().First();
control.ItemCheck += control_ItemCheck;
}
void control_ItemCheck(object sender, DevExpress.XtraEditors.Controls.ItemCheckEventArgs e)
{
var checkedListBoxControl = (CheckedListBoxControl)sender;
var current = checkedListBoxControl.Items[e.Index];
}
Use e.Index to get current item changed.
More information here and here.

Executing an action only when I select an item form the combo box

I have a ComboBox and in the form's load event it's populated with data. Now when I select an Item form the ComboBox, it should perform some actions. So I know few events which can be used in this case like
SelectedIndexChanged
SelectedValueChanged
etc.
But the problem is those events are raised even when setting the DataSource of the ComboBox and selecting a default index etc. when the form is loaded.
ComboBox1.DataSource = dt;
ComboBox1.SelectedIndex = -1;
What am I trying to do is that I just want to execute an action only when I select an item form the combo box. Is there a mouse event that could be used in this case?
The comboBox.SelectionChangeCommitted Event seems to do that.
Otherwise you could set a boolean value before you bind the datasource which you can use inside the event to ignore it.
private bool blnIgnoreEvent = false;
// in Form_load
blnIgnoreEvent = true;
ComboBox1.DataSource = dt;
blnIgnoreEvent = false;
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (!blnIgnoreEvent)
{
// go ahead
}
}
I don't believe there is another event that better handles what you'd like to do. XIVSolutions has a neat work-around for the event firing when you bind the data source: How to prevent selectedindexchanged event when DataSource is bound?
Also, since SelectedIndexChanged works for all cases, why not just handle the first?
if (ComboBox1.SelectedIndex == -1)
{
return;
}
If -1 corresponds to a value you'd like to be able to select, just use a private field to store some bool that you check to determine whether or not it is the first time the action has been executed.

How to set checkbox.isChecked without raising event

Is there a way of checking the CheckBox without running the code associated to checking it? Just for visual appearance.
Edit:
private void normalCheck_Checked(object sender, RoutedEventArgs e)
{
normal();
}
Imagine that I want to set the normalCheckBox.IsChecked=true; but without raising the event. Is that possible?
One way would be to detach the event handler, set the IsChecked property, and then reattach it.
myCheckbox.Checked -= myCheckbox_Checked;
myCheckbox.IsChecked = true;
myCheckbox.Checked += myCheckbox_Checked;
You could use the Click event instead of Checked and use the state of the checkbox like below:
private void normalCheck_Click(object sender, RoutedEventArgs e)
{
if (normalCheck.IsChecked ?? false) { normal(); }
}
Then, this event won't be raised by using normalCheck.IsChecked = true;. It will only be raised by a click.
NOTE: The null-coalescing operator (??) is necessary because IsChecked returns a bool? type which could be null.
For Unchecked Event : ( based on the solution of #keyboardP )
myCheckbox.Unchecked -= myCheckbox_Unchecked;
myCheckbox.IsChecked = false;
myCheckbox.Unchecked += myCheckbox_Unchecked;
If you're referring to changing the checked status without raising the "_Checked" event, you will likely have to override the event handler with a param to tell it to skip the event or not.
Related answer: Change Checkbox value without raising event

TreeView fires the BeforeSelect event multiple times

I am using the Windows Forms TreeView control.
The way i have it hooked up is as followed (simplified):
TreeView treeView = new TreeView();
treeView.BeforeSelect += beforeSelect;
private void beforeSelect(sender, args)
{
MessageBox.Show("Some msg");
// more code
}
In certain scenarios, the call to MessageBox.Show triggers another raising of the BeforeSelect event, which triggers another, and another, ...
It seems this event is raised PER ITEM in the treeview (i have counted the number of times it is raised).
I have searched all over the internet on more information for why this could occur.
One thing i've found was that TreeView will automatically select the first node when gaining focus.
This does not explain however why the event is fired as the number of treenode items in the tree.
Any help would be appreciated on this. I am considering raising a Microsoft Connect bug for this, as it seems like a very weird behavior that is not consistent with how i think the control should work.
Would it be enough to simply block yourself like the following?
private bool _inside;
private void beforeSelect( object sender, EventArgs args )
{
if ( !_inside )
{
_inside = true;
MessageBox.Show("Some msg");
// more code
_inside = false;
}
}
This would disallow "recursive" calls of your function.
the BeforeSelect event isn't fired multiple times by default.
when you select a node, you show a dialog(here messagebox) which interrupts the selection event or task however and after you close the dialog the selection event fires again based on the interruption. You should use AfterSelect event of the treeview to do things... and BeforeSelect only for validation..
Please look at this code - run it
void treeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
e.Node.Tag = (int)(e.Node.Tag ?? 0) + 1;
int count = (int)(e.Node.Tag);
e.Node.Text = String.Format("selected {0} Count: {1}", e.Action.ToString(), count);
}
When you define an object,you should write like this;
True Write:
private static TreeView projectagac;
...
...
...
projectagac = new TreeView();
thus you will create only one object.

Avoid calling indexchanged event when filling datasoruce

I'm filling a combobox with the datasource property in a c# winform app. In the other hand, I'm firing up an action with the SelectedIndexChanged of the same combo. The problem is that whenever the combo is filled with datasource the SelectedIndexChanged is called and I just want this event to be called when the user in fact does a selection.
Is there a way to avoid calling this event when filling the combo?
This is some of my code
//Filling the combo with some data
combo_cliente.DataSource = clientes;
combo_cliente.DisplayMember = "NomComp";
combo_cliente.ValueMember = "IDPersona";
private void combo_cliente_SelectedIndexChanged(object sender, EventArgs e)
{
// Here is the action to be triggered when user perfoms a selection
}
Thanks
Maybe unsubscribe and then subscribe again:
combo_cliente.SelectedIndexChanged -= combo_cliente_SelectedIndexChanged;
combo_cliente.DataSource = clientes;
combo_cliente.SelectedIndexChanged += combo_cliente_SelectedIndexChanged;
im assuming you assigned the event handler with the designer so they are bound when the control is instantiated. alternatively you could assign them in code after populating the controls.
Attach your event handler in your code behind instead of doing it on your aspx page and do it affer you have finished loading your control.
you need to add a blank record as the first of your combobox. Then in your code, you can write this;
private void combo_cliente_SelectedIndexChanged(object sender, EventArgs e)
{
if!(comboBox1.SelectedValue.ToString()== string.Empty)
{
//Here is the action to be triggered when user perfoms a selection
}
}

Categories