Prevent circular event chaining on UI controls when updated programmatically - c#

I have a CheckedListBox which contains many items which can be checked or unchecked individually.
Next to this are CheckBoxes representing supersets of the many items opposite. These are tri-state corresponding to what portion of their items are selected opposite.
Both the CheckedListBox and individual CheckBoxes subscribe to check changed type events which is causing a circular reference and overflow. How can I disable one from receiving change events when the other is updating it, programmatically?

void checkBox1_N_CheckStateChanged(object sender, EventArgs e) {
checkedListBox1.ItemCheck -= this.CheckedListBox1_ItemCheck;
// Handler body where affecting CheckedListBox1.
checkedListBox1.ItemCheck += this.CheckedListBox1_ItemCheck;
}
It works best to disable each others' event handlers as the other is updating.
void CheckedListBox1_ItemCheck(object sender, EventArgs e) {
//Find which 'i' is affected.
arrOfCBox[i].cb.CheckStateChanged -= arrOfCBox[i].eh;
// Handler body where affecting checkBox[i].
arrOfCBox[i].cb.CheckStateChanged += arrOfCBox[i].eh;
}
where BoxHandler is, at a minimum:
class BoxHandler
{
public EventHandler eh;
public CheckBox cb;
}
Similar to WinForms: temporarily disable an event handler, but amazingly that didn't get awarded an answer, (prolly too abstract?).

Related

Suppress AfterSelect event while moving a node in a TreeView

I am moving a TreeNode in a Windows Forms TreeView control as a consequence of a DragDrop event:
void treeViewDragDrop(object sender, DragEventArgs e)
{
// ...
sourceNode.Remove();
targetNode.Nodes.Add(sourceNode);
}
However, the Remove call triggers the AfterSelect event of the TreeView, which I need to react to if the selection really changes.
But in this case, the apparent selection change is only a result of temporarily removing the node. I don't want the selection to change at all after the node has finally moved to its target location in the tree.
So what would be the correct way to deal with that situation, i.e. how to suppress selection changes due to moving nodes?
If you do not set selection programmatically, you can cancel the selection in BeforeSelect event if the action is not user-generated:
private void TreeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
if (e.Action == TreeViewAction.Unknown)
e.Cancel=true;
}
If you change selection programmatically, you may use a simple workaround by extending the TreeView class and setting a sort of "flag":
public class MyTreeViwe : TreeView
{
public bool IsSuspendSelection { get; set; }
protected override void OnBeforeSelect(TreeViewCancelEventArgs e)
{
if (IsSuspendSelection)
e.Cancel = true;
else base.OnBeforeSelect(e);
}
}
then do:
var tv = sourceNode.TreeView;
tv.IsSuspendSelection=true;
sourceNode.Remove();
tv.IsSuspendSelection=false;
You could also unsubscribe and then subscribe again to the AfterSelect event on sourceNode.TreeView, but I personally find this method accident-prone. There's no way to know if a given delegate is currently subscribing to a given event, and how many times. You may end up subscribing to the event multiple times and then your AfterSelect delegate method will run more than once.

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.

C# WPF/XAML Preview Mouse Event for DataGrid

I'm using a WPF DataGrid with c#/xaml in Visual Studio 2013.
With SelectionMode="Extended", I'm able to multi-select rows in the grid.
I have a requirement where clicks on one of the columns of the grid are to be ignored relative to row selection.
I setup a PreviewMouseLeftButtonDown event that gets called.
Since it's a preview event, at the time of the event is processed, the selection in the grid hasn't changed yet.
I'm able to determine the row and column of the click, so I can determine a click has been made in a column that I don't want
I want to be able to abort the click event at that point so that no change is made to the current selected items in the grid. Is that possible?
In the mouse down event I tried something like:
private void GridCtrl_MouseDown(object sender, MouseButtonEventArgs e)
{
// ... Other code
e.Handled = true;
}
But, despite being marked as handled, it still continues and performs the row selection.
I also have a 'SelectionChanged' event that I see that it later gets into.
I think you actually need to handle both tunneling events - one for PreviewLeftMOuseButtonDown and another for PreviewSelectionChanged.
My advice is create a flag, let's call it:
bool _cancelSelectionChange = false;
Then, in your Mouse handler:
private void GridCtrl_MouseDown(object sender, MouseButtonEventArgs e)
{
_cancelSelectionChange = false;
// ... Other code
_cancelSelectionChange = true;
e.Handled = true;
}
Finally, in your selection change handler for the tunneling event:
private void GridCtrl_PreviewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
e.Handled = _cancelSelectionChange;
}

C# combobox appropriate event type

I have a combobox and with this I have a associated event
private void comboBox8_SelectedIndexChanged(object sender, EventArgs e)
{
}
My comobox is populated with two items a and b
I am setting combobox8.selectedItem = x where x= a or b. My event only fires if I select a from b or b from a. It does not fire if I again select a from a.
How can I do it and what's the appropriate event to deal with it ?
Moreover I am doing it all programmatically.
It makes sense that the event doesn't fire again. The selected item doesn't change. Depending on what you actually want, there are a lot of events you can utilize. You might start with Click, or DropDown, or DropDownClosed, for instance.
It won't fire because Selected Index did not change...
Take a look at msdn documentation for a list of comboBox events:
http://msdn.microsoft.com/en-us/library/system.windows.forms.combobox_events.aspx
You'll find out you can use more one depending on what you want to achieve (leave,lostfocus, [...])
Because the index did not change, the event is not fired. Since you need this processing when you are refreshing the form programmatically, call the appropriate code programmatically as well:
private void comboBox8_SelectedIndexChanged(object sender, EventArgs e)
{
ProcessComboBoxInput();
}
private void RefreshFormProgrammatically()
{
// Refresh the form here...
ProcessComboBoxInput();
}
private void ProcessComboBoxInput()
{
// Process the comboBox8 here...
}
Because its selected index changed event. From a to a nothing has been changed. You can try onclick event.

Is there anyway to prevent some event fired before end of another event?

In the code below the SelectionChanged event is fired before the end of RowsAdded,how can I make the Event atomic?
private void dataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
dataGridView1.CurrentCell = dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[1];
dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[1].Selected = true;
}
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow != null)
{
//Something
}
}
what should i do?
SelectionChanged is fired in the middle of handling RowsAdded because you are causing a SelectionChanged by changing the current cell within dataGridView1_RowsAdded. Adding a row doesn't cause both events to be fired -- you're causing the second event while handling the first one. (In fact, you're probably causing SelectionChanged twice, because both lines in the handler seem to change the selection).
If you don't want dataGridView1_SelectionChanged running while in the RowsAdded handler, you need to either temporarily unsubscribe from the event:
dataGridView1.SelectionChanged -= dataGridView1_SelectionChanged;
// change the selection...
dataGridView1.SelectionChanged += dataGridView1_SelectionChanged;
Or even better, re-design what you're doing inside the SelectionChanged handler so that it is appropriate for all instances of the event.
You can override the event you want to conrol and then put an if condition in the overriden event and control when it fires and when it does not.
mahdi

Categories