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.
Related
I have an ASP DropDownList control with the AutoPostBack property set to true. When the user changes the selection, the form posts back as expected. I want to know how to determine, in the code-behind, whether the page posted back for this specific reason.
I know that I can define an event handler like this...
protected void MyDropDownList_SelectedIndexChanged(object sender, EventArgs e) {
// Run some code if the selection for the "MyDropDownList" control was changed
}
...but what I want to know is how to check whether the form posted back because the selected index was changed outside the event handler.
Specifically, in the Page_Load() method, I have an if (IsPostback) {} section, and I want this section not to execute if the postback was caused by changing the selection in the DropDownList. So, in pseudocode, I want something like:
if (IsPostback && (! <DropDownList's selection was changed, causing an autopostback>)) {
I tried defining a global boolean variable and setting it to true in an event handler, then checking it in Page_Load(), like this:
public partial class MyWebApp : System.Web.UI.Page {
[...]
static bool selectedIndexChanged = false;
[...]
protected void DomainDropDownList_SelectedIndexChanged(object sender, EventArgs e) {
selectedIndexChanged = true; // Set this flag to true if selected index was changed
}
[...]
protected void Page_Load(object sender, EventArgs e) {
[...]
if (IsPostBack && selectedIndexChanged == false) {
[...]
}
[...]
This didn't work for a reason I presume experienced ASP.NET developers will easily spot: the event handler executes after Page_Load(), regardless of the order of the code.
I also tried to see if the control's selectedIndexChanged event can be used as a boolean condition to determine if the event triggered, like this
if (IsPostBack && !MyDropDownList.SelectedIndexChanged) {
but Visual Studio gives me the following error:
The event 'System.Web.UI.WebControls.ListControl.SelectedIndexChanged' can only appear on the left hand side of += or -="
A search on the error message led to this answer, but that doesn't seem to help because it relies on the event handler, which executes after Page_Load().
In my particular use case, where there is only one DropDownList and only one other way to submit the form (the submit button), it would be equally effective to check whether the selected index was changed, whether an AutoPostBack was triggered, or whether the submit button was clicked, but I'd also like to know how to do this in a broader range of scenarios, for example if there are multiple AutoPostBack controls and/or multiple ways to submit the form other than AutoPostBack.
So, my question breaks down as follows (though some of these may be essentially the same question, depending on what the answer is):
Is there a way to determine in general whether an AutoPostBack was triggered, as opposed to the form posting back for any other reason, such as clicking a button?
Is there a way to determine if a specific control's AutoPostBack was triggered (i.e. if there are multiple controls with AutoPostBack true, can it be determined which control caused the AutoPostBack)?
Is it possible to check in the Page_Load() method or any other code that executes before the SelectedIndexChanged event handler whether a DropDownList's selected index was changed?
If there's a better way to achieve what I'm trying to accomplish in this particular case, I'm open to suggestions, but I'd still like to know the answer(s) to the above.
During Page_Load inspect Page.Request.Form["__EVENTTARGET"]. This will contain an identifier representing the control that caused the post back. From this you should be able to determine whether the post back was caused by the control you're interested in.
if (IsPostBack && Request.Form["__EVENTTARGET"] != "<control ID>") {
...
}
Is it possible to check in the Page_Load() method or any other code that executes before the SelectedIndexChanged event handler whether a DropDownList's selected index was changed?
Not without resorting to a custom technique. The SelectedIndexChanged event fires too late during the page event lifecycle to be useful to your scenario. One option is to store the DropDownList.SelectedIndex into the Page.ViewState collection during Page.OnPreRender and then comparing this value to the new DropDownList.SelectedIndex on the post back during Page_Load.
I have a WinForm which contains a multitude of controls interdependent on each other for their visibility and content.
I have a pair of radio buttons, controlling a combobox's (ComboBoxA) enable/disable flag and content. The selection on this combobox controls the visibility of a checkbox. The checking of this checkbox controls another combobox's (ComboBoxB) visibility and content. Business requirements are quite complicated around these controls. As a result, I require the ability to fire of the events programmatically and through user action, doing different things in each case.
In the checkbox's case, I check it programmatically while loading data (if needed), which fires the CheckedChanged event which in turn does additional action controlling ComboBoxB. The code for this is pretty vanilla, nothing special, but my question is more theoretical than practical. Please keep reading.
Due to this requirement, I need a way to distinguish between programmatic checking and user action. I tried using the Click event and CheckedChanged event, setting a flag in the click event, signifying user action. Unfortunately, the CheckedChanged event fires before the Click event, dead-ending this trick.
Now, I tried using the MouseDown event to capture user action. But funnily enough, once the event fires, checkbox remains unchecked and the CheckedChanged event doesnt fire.
Now, I have managed to use a flag in the code to determine programmatic checking and use that to distinguish between the two, but I was curious as to why the MouseDown event didnt allow the checkbox to be checked. Any ideas? I searched online but either I didnt do a thorough job of it, or google is not returning the right results for me. I apologize if anybody is actually able to find a google result for this problem.
It's something else in your code, not the MouseDown event that's preventing the CheckChanged to be fired.
Here is how I know this:
I've added a checkbox and a button to an empty form, and added event handlers to Click on the button, and on the checkbox CheckedChanged, KeyDown and MouseDown events. I've also added to the form a string variable called LastEventRaised, and in the CheckedChanged I've simply shown a MessageBox:
string LastEventRaised = string.Empty;
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
MessageBox.Show("Checked changed " + LastEventRaised);
LastEventRaised = string.Empty;
}
private void checkBox1_KeyDown(object sender, KeyEventArgs e)
{
LastEventRaised = "KeyDown";
}
private void checkBox1_MouseDown(object sender, MouseEventArgs e)
{
LastEventRaised = "MouseDown";
}
private void button1_Click(object sender, EventArgs e)
{
LastEventRaised = "programmatically";
checkBox1.Checked = !checkBox1.Checked;
}
Each time the message box popped up I've got the correct message.
Sometimes while the user is typing text in a DataGridViewTextBox you want to enable or disable a control, depending on the value being typed. For instance enable a button after you typed a correct value
Microsoft showed the way in an article about how to create a DataGridViewButtonCell that can be disabled.
This is their trick (it can also be seen in other solutions)
Make sure you get the event DataGridView.CurrentCellDirtyStateChanged
Upon receipt of this event, commit the changes in the current cell by calling:
DataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
This commit will lead to the event DataGridView.CellValueChanged
Make sure you get notified when this event is raised
In your OnCellValueChanged function, check the validity of the changed value and decide
whether to enable or disable the corresponding control (e.g. button).
This works fine, except that the CommitEdit makes that the text is selected while in OnCellValueChanged. So if you want to type 64, you get notified when you type 6 and later when you type 4. But because the 6 is selected you don't get 64, but the 6 is replaced by 4.
Somehow the code must deselect the 6 in OnCellValueChanged before interpreting the value.
The property DataGridView.Selected doesn't do the trick, it doesn't deselect the text, but it deselects the cell.
So: how to deselect the text in the selected cell?
I think you need something that when the user is typing some text into the current cell, you need to know the current text (even before committing it) to check if some button need to be disabled. So the following approach should work for you. You don't need commit any thing, just handle the TextChanged event of the current editing control, the editing control is exposed only in the EditingControlShowing event handler, here is the code:
//The EditingControlShowing event handler for your dataGridView1
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e){
var control = e.Control as TextBox;
if(control != null &&
dataGridView1.CurrentCell.OwningColumn.Name == "Interested Column Name"){
control.TextChanged -= textChanged_Handler;
control.TextChanged += textChanged_Handler;
}
}
private void textChanged_Handler(object sender, EventArsg e){
var control = sender as Control;
if(control.Text == "interested value") {
//disable your button here
someButton.Enabled = false;
//do other stuff...
} else {
someButton.Enabled = true;
//do other stuff...
}
}
Note that the conditions I used above can be modified accordingly to your want, it's up to you.
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.
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