Issue in CheckedChanged event - c#

I have a check box and I have subscribed for the CheckedChanged event. The handler does some operations in there. I check and uncheck the checkbox programmatically (ex: chkbx_Name.Checked = true), and the CheckedChanged event gets fired.
I want this event to be fired only when I manually check or uncheck it. Is there any way to avoid firing of this event when i check/uncheck it programmatically?

unsubscribe the event before you set:
check1.CheckChanged -= check1_CheckChanged;
then you can programmatically set the value without the checkbox firing its CheckChanged event:
check1.Checked = true;
then re-subscribe:
check1.CheckChanged += check1_CheckChanged;
[EDIT: March 29, 2012]
The problem with Tanvi's approach is you need to catch all source of manual check or uncheck. Not that there's too many(it's only from mouse click and from user pressing spacebar), but you have to consider invoking a refactored event from MouseClick and KeyUp(detecting the spacebar)
It's more neat for a CheckBox(any control for that matter) to be agnostic of the source of user input(keyboard, mouse, etc), so for this I will just make the programmatic setting of CheckBox really programmatic. For example, you can wrap the programmatic setting of the property to an extension method:
static class Helper
{
public static void SetCheckProgrammatically(
this CheckBox c,
EventHandler subscribedEvent, bool b)
{
c.CheckedChanged -= subscribedEvent; // unsubscribe
c.Checked = b;
c.CheckedChanged += subscribedEvent; // subscribe
}
}
Using this approach, your code can respond neatly to both user's mouse input and keyboard input via one event only, i.e. via CheckChanged. No duplication of code, no need to subscribe to multiple events (e.g. keyboard, checking/unchecking the CheckBox by pressing spacebar)

No. Those property change events fire whenever the property value changes, regardless of whether this was done by your code, by the control's own code or databinding. It's all the same code path, usually.
What you can do, however, if your event handler resides in the same class as the code that changes the property value, is to introduce a private boolean field in the class which you use as an indicator of whether the current property change is triggered by your code or by the user. After your change you simply reset it. The event handler would then look at the field and decide of whether it should do anything or not:
class Foo : Form {
private bool checkedProgrammatically = false;
void someMethod() {
// ...
checkedProgrammatically = true;
checkBox1.Checked = true;
checkedProgrammatically = false;
// ...
}
private void checkBox1_CheckChanged(object sender, EventArgs e) {
if (checkedProgrammatically) return;
// ...
}
}

I'm sorry I can't just comment on Michael Buen's answer due to my being new here (no reputation), but for what it's worth I strongly prefer his solution to Johannes Rössel's for a couple of reasons.
1) the checkedProgrammatically variable is a little too close to global for me. There's nothing to stop another method accidentally setting it to true, causing all your events to stop.
2) you could end up with a lot of variables depending on the number of events you're dealing with. It would be easy to change the wrong one and the results can be difficult to debug.
3) it's more obvious what you're doing when you unsubscribe then resubscribe. All the logic is right there, and you don't need to change your event handlers to exit early depending on certain conditions.
I've used both methods extensively and I find Michael's a lot easier in the long run.

You can use the MouseClick event and in that check for the checked state of the checkbox.
This way it wont be triggered programatically, it would only be called when the user manually checks or unchecks the checkbox.

You can set boolean variable before changing value programiticaly, and check than reset that variable in checkedchanged event

Related

WP8 C# Button Change Click

I am programming in C# for Windows Phone 8 and have a Windows.System.Controls.Button object which does not have a "Click" event defined in the XML upon page load. However, after certain pieces of data are obtained, I want to set the button's click event to a specific function I have written.
How can this be done? The "OnClick" event is protected, and I can't find which setting to change in the MSDN site.
from the code you should be able to do something like MyButton.Click += clickhandler, from the XAML you also can do that.
You can potentially change the click event of the button by doing the following:
btButton.Click += NewHandler()
Another way, which isn't as clean would be to have a flag that checks if you have reached a specific stage, declared globally.
bool myBool = false;
Then you can change the bool flag to true and check whether it's true in the click event:
if(myBool)
{
//toDo Logic
}
This way you won't need to create another event handler.

Displaying a MessageBox prevents IsChecked from firing

I have a few TextBoxes that are bound to a single CheckBox.
This is the logic associated with it:
If the Checkbox is checked, it will overwrite any existing text in the associated TextBoxes and make it '0'++
If all of the TextBoxes have a score of '0,' the CheckBox should
become disabled and checked.
If any of the TextBoxes then change from '0,' it will become
enabled and unchecked.
++ *Note:* The caveat to this is if the TextBox has a value of 'C.'
Okay, so the issue I have is implementing the caveat above when one of the associated TextBoxes has a value of 'C.' What I would like to have happen is loop through the TextBoxes and check to see if any are scored 'C.' If one is found, display a warning message to the user confirming if they want to proceed. If Yes is selected, all associated scores will be overwritten to '0.' If No is selected then the Checked event should be cancelled.
To accomplish this, I added Event Listeners for the CheckBox.PreviewMouseDown and CheckBox.Checked events. Here is the code for my CheckBox.PreviewMouseDown event listener:
private void NormalCheckBoxControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
CheckBox normalCheckBox = (CheckBox)sender;
bool showCorrespondingScoreWarningMsg = false;
//Get a Row to loop through the AssociatedAdqScore controls for each
ScoreControl tempScoreControl = new ScoreControl();
foreach (ScoreControl score in this.ScoreControlList)
{
if (score.ScoreTextBox.Text == "C")
{
showCorrespondingScoreWarningMsg = true;
}
}
if (showCorrespondingScoreWarningMsg)
{
MessageBoxResult msgResult = InformationBox.Show("WARNING: Proceeding will remove corresponding 'C' scores. Continue?", "Continue?", ButtonStyle.YesNo, IconStyle.Question);
if (msgResult == MessageBoxResult.No)
{
e.Handled = true;
}
}
}
This works if the user selects 'No,' however the issue I'm having is that when choosing 'Yes,' the CheckBox.Checked event still does not get fired. I have tried to manually set CheckBox.IsChecked = true; if if (msgResult == MessageBoxResult.Yes), but this breaks the bindings so that is not a viable solution.
Is there any way I can resolve this issue and proceed with the NormalCheckBoxControl_Checked(object sender, RoutedEventArgs e) event if the user selects 'Yes?'
I don't know of a "Checked" event, though there is a CheckedChanged event and also a CheckStateChanged event. I am used to .NET 2.0, so this may be a 3.0+ thing. Either way, I think I have manually called the event handler in instances like this without any problem.
You can manually call the event handler with null params (or known object & new event args):
NormalCheckBoxControl_Checked(null, null);
or
NormalCheckBoxControl_Checked(new object, new EventArgs());
This should manually kick off your routine, and unless you need them, then there's really no problem with providing dummy params. No need to raise an event and wait for it to bubble, just call the routine.
Of course, if there are other routines which rely on the event bubbling or if you have multiple handlers for the same event, then it might cause you a problem. Be aware of that, just in case.

Change button on-click event creating exponetially increasing events

Have a simple application with a start/stop button that I want to do different things depending on it's current state. If button is in Start state, execute code then change to stop state and change OnClick event to StopButton_Click and vice versa.
Can't seem to change the on-click property of the button, so using code below which works, but keeps adding instances of the event. First click executes once, second click executes twice, third executes four times, ad infinitum.
StartButton.Click += new System.EventHandler(StartButton_Click);
alternates with
StartButton.Click += new System.EventHandler(StopButton_Click);
Is there a way to REPLACE the OnClick handler instead of adding to it?
Try removing the event handler before adding a new one:
StartButton.Click -= StartButton_Click;
One option is to remove the previous event handler before adding another, but a simpler option is to just use a single event handler. The event handler can look at some internal state field to determine what to do; this will likely be easier than constantly adding/removing event handlers.
It may look something like this:
private void buttonClick(object sender, EventArgs args)
{
if(buttonState == MyStateEnum.Start)
PerformStartAction();
else if(buttonState == MyStateEnum.Stop)
PerformStopAction();
}
Then instead of adding/removing event handlers you just need to assign a different value to buttonState.
+= works with events as it does anything else. It adds to what is already there.
Try removing the existing event handler with -= and then adding the new one.

Fire comboBox SelectedIndexChanged only from user click

I wrote a method to handle a comboBox's SelectedIndexChanged event.
In the constructor I populated the comboBox, and this activated my event-handling method. Which I don't want since nobody clicked on the comboBox.
Is there an easy way to get the comboBox not to fire the event unless the user clicked it?
If that is not possible, is there a way to disconnect the event to the method temporarily? Could I just set "my_combo.SelectedIndexChanged = null" and then create a new System.EventHandler?
Or I guess I could create some kind of boolean member variable that I can switch on or off and put a branch check in my method. That seems like a kludge, though.
I have done it a lot number of times.
Solution1: Delete EventHandler from designer. Populate the combobox and then set EventHandler.
Combo1.SelectedIndexChanged += new EventHandler Combo1_SelectedIndexChanged;
But it will work only if you are populating the combobox once.If you are doing it for many number of times, then you may be in a mess.
Solution2: Its my preference and I use it regularily.
Change your selection change event as:
private void cb1_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
if(!cb.Focused)
{
return;
}
// Here is your Code for selection change
}
So now the event will be fired only if its in focus. Hope you were looking for the same.
Hope it Helps
Not sure if this is any use now but I found this answer, which seems cleaner to me.
From the MSDN Library - ComboBox.SelectionChangeCommitted Event
"SelectionChangeCommitted is raised only when the user changes the combo box selection. Do not use SelectedIndexChanged or SelectedValueChanged to capture user changes, because those events are also raised when the selection changes programmatically."
You can use both methods You proposed:
use boolean variable
detach event method, populate combobox, attach event method like this
my_combo.SelectedIndexChanged -= my_Combo_SelectedIndexChanged;
populateCombo();
my_combo.SelectedIndexChanged += my_Combo_SelectedIndexChanged;
my_Combo_SelectedIndexChanged is the name of method you attached to the event.
I would use control.ContainsFocus instead of creating other bool. The caveat here is that you have to make sure the user has focus on that control. Either by key or mouse.
if(combo.ContainsFocus){ MyEventLogic();}
Solution: If you're populating combobox with static values only ones, just populate them and after subscribe to event from code. Do not use WinForms Designer to subscribe to it.
If it's not possible during loading can:
a) define a boolean variable bool loading, set it to true before you begin to populate combo with data, and in event handler check
if(loading)
return;
b) Unsubsribe from event:
If subscription was:
comboBox.SelectedIndexChanged += delegate(...);
Unsubscription before you begin load data is:
comboBox.SelectedIndexChanged -= delegate(...);
As loading of data finished, subscribe again.

Is it possible to subscribe one control to the same event handler multiple times?

I would like to know if I bind the TextChanged event handler to a TextBox control, then how can I ensure that won't be allowed to bind this event handler again?
You can't ensure that. You would theoretically be allowed to bind the same event handler to a textbox (or other control) more than once. The only thing that events allow you to do is add a handler and remove a handler—there's no additional means provided to check for existing subscribers. If you don't believe me, Jon Skeet provides the authoritative answer here, and in his article on events.
If you need to ensure that you don't accidentally subscribe a control to the same event twice, you'll need to keep track of it yourself. Honestly, you should never end up in a situation where you don't know what event handlers are subscribed. Not only does this reflect sloppy design, but it probably also means that you aren't taking care to remove your event handlers when they are no longer necessary.
A possible solution is provided in the answers to this question, but I caution you from using something like this blindly. As others have argued, this code is something of an anti-pattern.
You can bind it programatically as many times as you'd like. If you want to prevent this you can use a List<object> to keep references in, for example:
private List gotRefs = new List();
public void MyMethod()
{
if (!gotRefs.Contains(txtTextBox1)) {
txtTextBox1.TextChanged += txtTextBox1_TextChanged;
gotRefs.Add(txtTextBox1);
}
}
You can actually use a hack.
You can make textbox private to your class to ensure, that only your single class is able to access the text box and add handlers to it.
private TextBox txtChanging;
Then, in your class, you can create a custom event like textBoxTextChanged
public event Action TextBoxTextChanged;
Create a standart method OnTextBoxTextChanged
private OnTextBoxChanged( object sender, EventArgs args )
{
if( TextBoxTextChanged != null )
TextBoxTextChanged();
}
Bind this OnTextBoxChangedMethod to TextChanged event of the TextBox
txtChanging.TextChanged += OnTextBoxChanged;
Ensure that NO OTHER METHOD is bound to TextChanged event of the text box
Bound all your main payload text changed handlers to your new custom event instead of text box textchanged event directly
TextBoxTextChanged += txtChanged_TextChnaged;
All that paperwork is because events actually provide a lot of information, but only to the methods inside the class where they are defined.
You can check bound delegates with
TextBoxTextChanged.GetInvocationList()
and their count with
TextBoxTextChanged.GetInvocationList().Count() //(C# 4.0/LINQ)
or just count them through foreach.

Categories

Resources