Prevent CheckBox Checked event from firing - c#

I have some CheckBoxes created dynamically on code. I do read a barcode using a barcode reader. I'm trying to stop the Unchecked and Checked events from firing when I'm using the barcode. For that effect I:
only assign both events when I get the focus on the Checkboxes, and when I lose the focus I take the events out.
after each Checked and Unchecked event I assign the focus to another control in the window (so the LostFocus event gets triggered)
But went I use the barcode reader, all of the CheckBoxes objects receive the Unchecked event if they were checked (but not the Checked event if they were unchecked).
Is there a way to prevent this from happening?
The only places where the Unchecked method is being used are the ones in the code show, nowhere else in the code of the application.
A pointer to a better way to handle this dynamic creation of Checkboxes will not go unappreciated.
private void SomeMethod ()
{
foreach (KeyValuePair<String, String> kvp in someDictionary)
{
CheckBox checkBox = new CheckBox();
checkBox.Content = kvp.Key;
checkBox.GotFocus +=new RoutedEventHandler(checkBox_GotFocus);
checkBox.LostFocus += new RoutedEventHandler(checkBox_LostFocus);
checkBox.ClickMode = ClickMode.Release;
Grid.SetRow(checkBox, fileSelectionGrid.RowDefinitions.Count);
fileSelectionGrid.Children.Add(checkBox);
RowDefinition row = new RowDefinition();
fileSelectionGrid.RowDefinitions.Add(row);
}
}
void checkBox_LostFocus(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
checkBox.Checked -= new RoutedEventHandler(checkBox_Checked);
checkBox.Unchecked -= new RoutedEventHandler(checkBox_Unchecked);
}
void checkBox_GotFocus(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
checkBox.Checked += new RoutedEventHandler(checkBox_Checked);
checkBox.Unchecked += new RoutedEventHandler(checkBox_Unchecked);
}
EDIT :
Just checked that the click event is not raised when the CheckBox doesn't have the focus.

Usually for such kind of problems i declare a bool flag which is assigned value before and after code line where an event will fire and when that event is fired the first thing it does is to check for that flag value.
For e.g.
bool flag = false;
private void SomeMethod()
{
flag = true;
YourCheckBox.checked = false;
flag = false;
}
void YourCheckBox_Checked(object sender, RoutedEventArgs e)
{
if (flag)
return;
// Do something....
}
void YourCheckBox_UnChecked(object sender, RoutedEventArgs e)
{
if (flag)
return;
// Do something....
}
When i assigned flag = true the next line will fire selection changed event. when i does it will return coz flag is set to true;

Instead of basing on loosing focus, try disabling your event handlers directly before barcode reading and enabling them afterward. Something like this:
public void ReadBarcode(ComboBox cmbx)
{
FieldInfo info = cmbx.GetType().GetField("SelectedIndexChanged", BindingFlags.Instance | BindingFlags.NonPublic);
if (info != null)
{
object obj = info.GetValue(cmbx);
if (obj is EventHandler)
{
EventHandler handler = (EventHandler)obj;
cmbx.SelectedIndexChanged -= handler;
//
// Perform your bar code reading here.
//
cmbx.SelectedIndexChanged += handler;
}
}
}
I have used a single combobox for clarity sake, obviously you can use the same technique for an array of comboboxes

I found a solution. I added event handlers for KeyUp and KeyDown (the barcode input is consider keystrokes) to the control that was receiving the focus with:
e.Handled = true;
and that stopped the checkboxes receiving them.
As per the documentation, it is a Bubbling event. And the control and the checkboxes are cousins
control->grid 1->parent grid
checkbox->grid 2->parent grid
I would not have expected it to go up to the parent grid and then down. I need to read more about WPF.
Seems to me a bit of a hack. If someone gets a better answer, I will mark it.

Related

Attaching 1 validating event handler to Multiple textboxes

OverView
I have researched out there an I know there is a vast amount of info subscribing multiple event handlers to a single event however, I have not been able to apply it to my scenario. Pretty much I have a bout 30 of these validation event handlers from a textBox, all doing he same process. Below is one of those handlers:
private void txt_HouseName_Validating(object sender, CancelEventArgs e)
{ // Convert User input to TitleCase After focus is lost.
if (Utillity.IsAllLetters(txt_HouseName.Text) | !string.IsNullOrEmpty(txt_HouseName.Text))
{
errorProvider.Clear();
txt_HouseName.Text = Utillity.ToTitle(txt_HouseName.Text);
isValid = true;
}
else
{
errorProvider.SetError(txt_HouseName, "InValid Input, please reType!!");
isValid = false;
//MessageBox.Show("Not Valid");
}
}
How would I minimizes my code to just one of these lines of code and only have one of these event handler?
I know I should attach them within the designer code something similar to this
this.txt_Fax.Validating += new System.ComponentModel.CancelEventHandler(this.txt_Fax_Validating);
But as they are textboxes How would I go about attaching 1 validating events handlers to all of my TextBoxes
You should be using the object sender parameter. as the sender is nothing but the object that called the Event Handler. So, have a global event handler and attach the same handler to all the text boxes. Your Event handler will look something like this.
private void txt_Validating(object sender, CancelEventArgs e)
{ // Convert User input to TitleCase After focus is lost.
//Cast the sender to a textbox so we do not need to use the textbox name directly
TextBox txtBx = (TextBox)sender;
if (Utillity.IsAllLetters(txtBx.Text) | !string.IsNullOrEmpty(txtBx.Text))
{
errorProvider.Clear();
txtBx.Text = Utillity.ToTitle(txtBx.Text);//using the cast TextBox
isValid = true;
}
else
{
errorProvider.SetError(txtBx, "InValid Input, please reType!!");
isValid = false;
//MessageBox.Show("Not Valid");
}
}
Since the object sender parameter is passed with almost every event, it makes it easy to have a common callback for similar events and just check the sender and perform specific operations.

Radio button checked changed event fires twice

Please read my question its not a duplicate one.
I've three radio buttons on windows form and all these buttons have common 'CheckedChanged' event associated. When I click any of these radio buttons, it triggers the 'CheckedChanged' event twice.
Here is my code:
private void radioButtons_CheckedChanged(object sender, EventArgs e)
{
//My Code
}
I inserted the breakpoint and the whole code within this event iterates twice.
Please tell me why it is behaving like this?
As the other answerers rightly say, the event is fired twice because whenever one RadioButton within a group is checked another will be unchecked - therefore the checked changed event will fire twice.
To only do any work within this event for the RadioButton which has just been selected you can look at the sender object, doing something like this:
void radioButtons_CheckedChanged(object sender, EventArgs e)
{
RadioButton rb = sender as RadioButton;
if (rb != null)
{
if (rb.Checked)
{
// Only one radio button will be checked
Console.WriteLine("Changed: " + rb.Name);
}
}
}
To avoid it, just check if radioButton is checked
for example:
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
if (radioButton1.Checked)
//your code
}
CheckedChanged is raised whenever the Checked property changes. If you select a RadioButton then the previously selected RadioButton is unchecked (fired CheckedChanged), and then the new RadioButton is checked (fired CheckedChanged).
It's triggering once for the radio button transition from checked to unchecked, and again for the radio button transitioning from unchecked to checked (i.e. any change in checked state triggers the event)
You could set the AutoCheck property true for each RadioButton then catch the Click event instead of the CheckChanged event. This would ensure that only one event is fired, and the logic in the handler can cast the sender to type RadioButton if needed to process the click. Often the cast can be avoided if the handler logic is simple. Here is an example which handles three controls, rbTextNumeric, rbTextFixed and rbTextFromFile:
private void rbText_Click(object sender, EventArgs e)
{
flowLayoutPanelTextNumeric.Enabled = rbTextNumeric.Checked;
txtBoxTextFixed.Enabled = rbTextFixed.Checked;
flowLayoutPanelTextFromFile.Enabled = rbTextFromFile.Checked;
}
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
int click = 0;
private void radioButton1_Click(object sender, EventArgs e)
{
click++;
if (click %2==1)
{
radioButton1.Checked = true;
}
if (click %2==0)
{
radioButton1.Checked = false;
}
if (radioButton1.Checked==true)
{
label1.Text = "Cheked";
}
if (radioButton1.Checked==false)
{
label1.Text = "Uncheked";
}
}
}
}
The other answers are correct but miss the reason for the underlying problem.
When a radio button is checked the first event sent is the change from the unchecked item
however if you check its state by its control name you will still see its old checked status because the form has not been updated yet. To see its true status you need to cast the sender object.
This allows you to perform any actions relating to the condition which is being deselected should you need to do so.
In the not uncommon scenario below multiple radio buttons are sent to the same handler event.
Simply checking the state of the sender for checked will not work here as we need to perform different actions depending on which radio button has been pressed.
So first we ignore any sender that has just been unchecked.
then we identify the checked sender by control name to process the correct action.
private void ModeChangedExample(object sender, EventArgs e)
{
// multiple radio buttons come here
// We only want to process the checked item.
// if you need to something based on the item which was just unchecked don't use this technique.
// The state of the sender has not been updated yet in the form.
// so checking against rdo_A check state will still show it as checked even if it has just been unchecked
// only the sender variable is up to date at this point.
// To prevent processing the item which has just been uncheked
RadioButton RD = sender as RadioButton;
if (RD.Checked == false) return;
if (rdo_A.Name == RD.Name)
{
//Do stuff
}
if (rdo_B..Name == RD.Name)
{
// Do other stuff
}
if (rdo_C.Name == RD.Name)
{
// Do something else
}
}
This problem of double checking happens when there is a series of RadioButton Clicks in succession.I had this same problem.The last click will give two results.To overcome this i made a dummy click in the end.The double click stopped.Try this method.
Venkatraman

2 events calling each other

I was wondering about this problem for a while, but couldn't really come up with a solution. I have 2 different event handlers calling each other recursively. As soon as event A is fired, it triggers event B which triggers event A again and so on...
Basically I want to be able to select text in a RichTextBox and show the corresponding font size in a combo box. When I choose a different font size from the ComboBox, I want it's value to be applied to the selected text.
The 2 events are:
1) The selection changed event of text inside a RichTextBox:
private void MyRTB_SelectionChanged(object sender, RoutedEventArgs e)
{
//Get the font size of selected text and select the concurrent size from the ComboBox.
}
2) The selected index changed event of a Combobox:
private void CmbFont_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//Apply the chosen font size to the currently selected text of the RichTextBox.
}
What would be the best solution to make sure they each only "do their thing" and do not fire the other event in doing so?
Sometimes changing a property of a control in code fires an event unintentionally. Changing the data source of a ListBox or a ComboBox will fire the SelectedIndexChanged event, for example. Use a flag to handle this case
private bool _loading;
...
_loading = true;
// Fill the ComboBox or ListView here
_loading = false;
In the event handler do this
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading) return;
...
}
Refactor your code so that A calls DoSomethingA() and B calls DoSomethingB(). This way, if you want A to do the functionality of B you can just call DoSomethingB() and not have any recursive calls.
Just use a bool (maybe called dontFireA) and set it in A just before calling B
notifying properties (used in order to enable binding from WPF to non-WPF properies) use this technique:
public object MyProperty
{
get
{
return myField;
}
set
{
if (value != myField)
{
myField = value;
NotifyProperyChanged("MyProperty"); // raise event
}
}
}
The if (value != myField) condition prevents infinite recursion (stackoverflowexception).
In some cases (e.g. floating point numbers and inaccurate value transfers) if (Math.Abs(value - myField) > someConstant) is used instead to break the recursion.
Could you apply a similar technique to your problem?
If both events are on the same object or the owners have references to each other, you could also store a flag on each e.g.
private void OnEvent()
{
DoSomething();
}
private void DoSomething()
{
this.IsBusy = true;
// do work
// raise event
if (!other.IsBusy)
RaiseEvent();
}
I am going to make the educated guess that you are not raising Event A or Event B yourself; let's say Event A is the TextBox1.TextChanged event and Event B is the TextBox2.TextChanged event, and they have handlers like:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
...
TextBox2.Text = someString;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
...
TextBox1.Text = someOtherString;
}
In this case, the handlers are each going to raise the other textbox's TextChanged event by virtue of changing the text, leading to infinite recursion.
The first thing you can do, if you want both to run once and once only, is to mark that they're already running (changing the text of the other textbox results in that textbox's event handler running within the same call stack:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
if(handler1Running) return; //the second time through we exit immediately
handler1Running = true;
...
TextBox2.Text = "Something"; //the other event handler is invoked immediately
handler1Running = false;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
if(handler2Running) return; //the second time through we exit immediately
handler2Running = true;
...
TextBox1.Text = "Something Else"; //the other event handler is invoked immediately
handler2Running = false;
}
Now, the deepest it will go is three levels; 1's handler invokes 2's handler which invokes 1's handler again, which sees that 1's handler is already running and quits before doing anything that would deepen the recursion. Same thing if you start by changing TextBox2.
The other thing you can do is make sure you aren't trying to set the textbox to the same value that's already there. Changing from one string reference to another, even if both references are the same string value, will fire the TextChanged event. If the recursion must continue naturally but will reach a steady state, this is actually the first thing to try:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox2.Text)
TextBox2.Text = builder.ToString();
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox1.Text)
TextBox1.Text = builder.ToString();
}

Hiding datagridviews bug

I have a windows form with a panel on the left, which consists purely of radiobuttons, and a tabcontrol in the middle, with multiple tab pages within it. Each of these individual tabpages have a series of datagridviews within it, which are shown and hidden depending on which radio button you check.
I accomplish this effect by having each of the radiobuttons on the left assigned a CheckChanged event, which loops through all of the controls within the tabpagecontrol.SelectedTab, and calls .Show() on the corresponding datagridview and calls .Hide() on the rest so that only one datagridview is visible at one time.
My problem occurs when i try to programmatically check one of these RadioButtons. Lets say in Method X, I write RadioButtonA.checked = true. This triggers the usual CheckedChange event handling, which loops through all the datagridviews on the currently selected tabpage and calls .Hide() on everything except the one datagridview form that the radiobutton is supposed to bring up and calls .Show() instead. However, on one of these .Hide() calls on the datagridview, it ends up triggering the RadioButtonA.CheckedChange event AGAIN for a second time. When i look at the sender argument passed to the function, it shows that the sender is the RadioButton i just programmatically clicked on.
I am adding these datagridviews programmatically and can confirm that there are no eventhandlers assigned whatsoever to them. Can anyone help me determine what is causing this additional event to get triggered? Thanks.
For obnoxious change events that trickle through and upset other event handlers on my forms, I've found the only solution is to add a small boolean value:
bool radioIng;
void MyMethod() {
radioIng = true;
try {
radioButton1.Checked = true;
// etc.
} finally {
radioIng = false;
}
}
void radioButton_EventHandler(object sender, EventArgs e) {
if (radioIng) return;
// rest of code here
}
EDIT:
Alternately, you could just remove all of your event handlers and reconnect them later:
void MyMethod() {
try {
radioButton1.CheckChanged -= radioButton_EventHandler;
radioButton2.CheckChanged -= radioButton_EventHandler;
radioButton3.CheckChanged -= radioButton_EventHandler;
// execute your code
radioButton1.Checked = true;
} finally {
radioButton1.CheckedChanged += new EventHandler(radioButton_EventHandler);
radioButton2.CheckedChanged += new EventHandler(radioButton_EventHandler);
radioButton3.CheckedChanged += new EventHandler(radioButton_EventHandler);
}
}
void radioButton_EventHandler(object sender, EventArgs e) {
if (sender == radioButton1) {
// code here to handle
} else if (sender == radioButton2) {
// code here to handle
} else if (sender == radioButton3) {
// code here to handle
}
}

Cancel uncheck in WPF

I use checkbox in WPF window. I use some logic in unchecked event of checkbox. And I want to cancel uncheck if need it in the body of this event. How can I do this?
private void chApprove_Checked(object sender, RoutedEventArgs e)
{
btnAddDepartment.IsEnabled = true;
brnRemoveDepartment.IsEnabled = true;
}
private void chApprove_Unchecked(object sender, RoutedEventArgs e)
{
if (lbSource.Count == 0)
{
btnAddDepartment.IsEnabled = false;
brnRemoveDepartment.IsEnabled = false;
}
else
{
MessageBox.Show("Staff already in use! Release it first from dependecies!");
CheckBox myCheckBox = e.Source as CheckBox;
myCheckBox.IsChecked = true;
}
}
Impossible to cancel uncheck !!!
void CheckBox1_Unchecked(object sender, RoutedEventArgs e)
{
if(ResultOfSomeLogic)
{
CheckBox myCheckBox = e.Source as CheckBox;
myCheckBox.IsChecked = True; // Check it again
}
else
{
}
}
Also take a look at EventToCommand Binding Behaviour in MVVM Light to take advantage of CanExecute method.
You could do this easily with an attached behavior (rather than using code behind), you can take a look at this answer if you need a sample of how to structure one (it's only a few lines of code).
My spider-sense is telling me this isn't a very good idea though - I can't imagine a way to "justify" rechecking a checkbox that a user has clicked, it just strikes me as very jarring. Can you not either bind the enabled state of the checkbox to a property on your ViewModel or, if you have an ICommand bound to it, use the CanExecute delegate to enable/disable it based on the same logic?
Bind the IsChecked property of check box. Like
IsChecked="{Binding IsChecked, Mode = TwoWay}"
and in your class define some thing like dis;
private bool isChecked;
public bool IsChecked
{
get
{
return this.isChecked;
}
set
{
this.isChecked = value;
OnPropertyChanged["IsChecked"];
}
}
and in your event
void CheckBox1_Unchecked(object sender, RoutedEventArgs e)
{
if(ResultOfSomeLogic)
{
this.IsChecked = true;
}
else
{
}
}
hope this will work for u..
Good Luck..
In my case, I could not use a solution that allowed unchecking in the first place. If the checked state initiates a critical asynchronous operation, it is not always ideal to uncheck just to check it again: Why allow cancelling this operation if it shouldn't have been allowed to cancel in the first place?
For MenuItems, you can subscribe to the PreviewMouseDown event and set IsCheckable to false; then subscribe to the Click event and set IsCheckable back to true. The reason this works is because IsCheckable just determines whether or not to initiate the state change, unlike IsHitTestEnabled="false" and IsEnabled="False", which will stop all events from firing.
If you try to disable it, no subsequent events will fire making it impossible to restore checkability; by making it uncheckable beforehand, we avoid this mistake. Click also happens to occur after the state would've been changed so it works out quite nicely.
Unfortunately, CheckBox does not have an equivalent IsCheckable property; however, the same concepts described above (i.e., PreviewMouseDown, Click pattern) can produce a similar, if not identical, result.
Well assuming a check box is intended to interact with users instead of programmatic ways, there's a simple way to cancel Unchecked events based on some logic when user hits left mouse button or space bar:
private void CheckBox_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// If it's already checked so next click would uncheck it hence trigger the Unchecked event.
if ((sender as System.Windows.Controls.CheckBox).IsChecked == true)
{
var isConfirmed = false; // Use your confirmation logic here instead.
// If e.Handled is set to false that will cancel further events such as the Unchecked event.
e.Handled = isConfirmed;
}
}
private void CheckBox_PreviewKeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
// If it's already checked so when user presses space bar it would uncheck it hence trigger the Unchecked event.
if ((sender as System.Windows.Controls.CheckBox).IsChecked == true)
{
if (e.Key == System.Windows.Input.Key.Space)
{
var isConfirmed = false; // Use your confirmation logic here instead.
// If e.Handled is set to false that will cancel further events such as the Unchecked event.
e.Handled = isConfirmed;
}
}
}

Categories

Resources