Cancel uncheck in WPF - c#

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;
}
}
}

Related

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

Prevent CheckBox Checked event from firing

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.

When you set Checked property in a RadioBox, can you suppress the CheckChanged event?

I'm new to C# and Windows Form but if I have a radiobutton and I call radiobutton1.Checked=true, is there a way for it to not fire the CheckedChange event? I want to distinguish between the user clicking on the radiobutton and me setting the radiobutton programmatically. Is this possible?
Stop trying to defeat the design of the CheckedChanged event. It's specifically supposed to include programmatic changes.
If you want user-triggered changes and not programmatic changes, use the Click event instead. (You may be thinking that you don't want to restrict yourself to mouse clicks, don't worry, there's a MouseClick event for that, Click includes keyboard changes as well.)
Here's a straightforward method of using the event when you feel like it.
private bool SuppressRadioButton1Event { get; set; }
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
if (!this.SuppressRadioButton1Event)
{
MessageBox.Show("Not suppressed!");
}
}
private void button1_Click(object sender, EventArgs e)
{
this.SetRadioButton1(false);
}
private void SetRadioButton1(bool checkedOn)
{
this.SuppressRadioButton1Event = true;
radioButton1.Checked = checkedOn;
this.SuppressRadioButton1Event = false;
}
A very easy way:
public void radio_OnCheckChanged(object sender, EventArgs e)
{
RadioButton r = sender as RadioButton;
bool isUserChange = r.Tag.Equals(1);
if (isUserChange) blabla
else blabla
r.Tag = null;
}
public void MyMethod()
{
radio1.Tag = 1;
radio.Checked = true;
}
You can use any kind of flag which users can't do by their clicking.But you can do via your code.
Why should your code care who checked the radiobutton?
EDIT: There are ways around this (subclass, flag), but don't. The only "legit" reason I can think of for wanting this is to prevent some side-effect from happening when the value is initially (programatically) displayed, and even that is suspect. Rethink the side-effect, does it really belong on the change-event, or the commit?
More info one why/what would help. On the surface, this looks like a design error.
One (hackish) way to do it would be to subclass RadioButton and override the OnCheckChanged virtual method, suppressing the event if the Checked property has been set programmatically.
However, since radio-buttons belong to a group, the event always fires in pairs (oen for the uncheck, one for the check). You will therefore want to suppress the event for the entire group when you choose the selected button programmatically. Here's an example implementation:
public class CustomRadioButton : RadioButton
{
private bool _suppressCheckedEvent;
public void SetChecked(bool value, bool suppressCheckedEvent)
{
if (!suppressCheckedEvent)
Checked = value;
else
{
SetSupressModeForGroup(true);
Checked = value;
SetSupressModeForGroup(false);
}
}
private void SetSupressModeForGroup(bool suppressCheckedEvent)
{
foreach (var crb in Parent.Controls.OfType<CustomRadioButton>())
crb._suppressCheckedEvent = suppressCheckedEvent;
}
protected override void OnCheckedChanged(EventArgs e)
{
if (!_suppressCheckedEvent)
base.OnCheckedChanged(e);
}
}
In this implementation, changing the checked-state through the Checked property will always fire the event. When you call the SetChecked method, you have the choice to suppress the event.
You could try to attach the event programmatically. Based on my application configuration I check several radio buttons but I don't want to fire events.
To attach an event programmatically:
chbOptionX.CheckedChanged += new System.EventHandler(this.chbShowStockBySizeAndColor_CheckedChanged);

Windows C# CheckedListBox Checked Item Event Handling

I'm currently developing a Window app that uses CheckedListBoxes for certain aspects of the program. A problem I've encountered is that I have been trying to find which event is triggered when an item is checked so that I can enable a form button when any list item is checked.
Problem is that I tried using the following;
private void clbAvailMods_ItemCheck(object sender, ItemCheckEventArgs e)
{
if(e.NewValue == CheckState.Checked)
{
btnInstall.Enabled = true;
}
}
but when I set a breakpoint on the if statement, it never fires upon checking an item in the listbox.
Am I doing something wrong here?
A standard Windows Forms trick is to delay running code until all event side-effects have been completed. You delay running code with the Control.BeginInvoke() method. This will fix your problem:
private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e) {
this.BeginInvoke(new MethodInvoker(evalList), null);
}
private void evalList() {
bool any = false;
for (int ix = 0; ix < checkedListBox1.Items.Count; ++ix) {
if (checkedListBox1.GetItemChecked(ix)) {
any = true;
break;
}
}
btnInstall.Enabled = any;
}
You can use the NewValue property to manually update CheckedItems.Count. This is the code I use to only enable a button when there's at least one item checked:
private void checkedListBoxProds_ItemCheck(object sender, ItemCheckEventArgs e)
{
this.buttonGenerar.Enabled = ((this.checkedListBoxProds.CheckedItems.Count + (e.NewValue == CheckState.Checked ? 1 : -1)) > 0);
}
A couple of potential gotchas. Presumably you've added the event through the VS.Net GUI to ensure that it gets plumbed into the control. Try clicking on an item twice - once to give the item focus and again to toggle the check state - if you want an item to have its check state toggled on first click then set the "CheckOnClick" property to true.
I think it is the SelectedIndexChanged event but I will confirm right now.
EDIT: SelectedIndexChanged event does work. But that is firing regardless of whether the checkbox was checked. So I would then check the checked state if you want to do that.
But as an aside when I did use the ItemCheck event it did fire when I actually checked the checkbox and not just the text.
I know this has been answered long ago, but I found it easier to just handle the MouseUp and KeyUp events. The CheckedItems.Count property is accurate when those events are fired. Since they both do the same thing, I created a method to to the work and called that method from both event handlers.
private void clbFolders_KeyUp(object sender, KeyEventArgs e) { Update(); }
private void clbFolders_MouseUp(object sender, MouseEventArgs e) { Update(); }
private void Update()
{
btnDelete.Enabled = clbFolders.CheckedItems.Count > 0;
}

How to prevent/cancel a combobox's value change in c#?

I have a combobox at the top of a form that loads editable data into fields below. If the user has made changes, but not saved, and tries to select a different option from the combobox, I want to warn them and give them a chance to cancel or save.
I am in need of a "BeforeValueChange" event with a cancelable event argument.
Any advice on how to accomplish?
Save the ComboBox's SelectedIndex when to box if first entered, and then restore it's value when you need to cancel the change.
cbx_Example.Enter += cbx_Example_Enter;
cbx_Example.SelectionChangeCommitted += cbx_Example_SelectionChangeCommitted;
...
private int prevExampleIndex = 0;
private void cbx_Example_Enter(object sender, EventArgs e)
{
prevExampleIndex = cbx_Example.SelectedIndex;
}
private void cbx_Example_SelectionChangeCommitted(object sender, EventArgs e)
{
// some custom flag to determine Edit mode
if (mode == FormModes.EDIT)
{
cbx_Example.SelectedIndex = prevExampleIndex;
}
}
Here is the simplest fix:-
bool isSelectionHandled = true;
void CmbBx_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (isSelectionHandled)
{
MessageBoxResult result = MessageBox.Show("Do you wish to continue selection change?", this.Title, MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.No)
{
ComboBox combo = (ComboBox)sender;
isSelectionHandled = false;
if (e.RemovedItems.Count > 0)
combo.SelectedItem = e.RemovedItems[0];
return;
}
}
isSelectionHandled = true;
}
Save the current value on the Enter event.
Implement the BeforeValueChange logic in the ValueChanged event, before the actual ValueChanged logic. If the user cancels, set the stored value and don't continue in the method (return).
If you're going to use this system a lot, I'd suggest inheriting ComboBox and implementing your BeforeValuechange event there.
The Validating event can be used for this scenario
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx
You don't get an appropriate event by default. You could cache the previous value and set it back to that if the user wants to cancel.
How about using the Validating / Validated events?
It works well, if the event happening on LostFocus instead of Change is ok with you.
Otherwise, how about
public void Combobox_ValueChanged(object sender, EventArgs e) {
if (!AskUserIfHeIsSureHeWantsToChangeTheValue())
{
// Set previous value
return;
}
// perform rest of onChange code
}
You could use a message filter to intercept clicks and key presses, which would allow you to prevent the combo box's normal behaviour. But I think you'd be better off disabling the combo box when the user makes a change, and require them to either save or revert their changes.
You can't really prevent it, but you can change it back to the old value if certain requirements aren't met:
private SomeObject = selectedSomeObject=null;
private void cbxTemplates_SelectionChangeCommitted(object sender, EventArgs e)
{
if (!(sender is ComboBox cb)) return;
if (!(cb.SelectedItem is SomeObject tem)) return;
if (MessageBox.Show("You sure?", "??.",
MessageBoxButtons.OKCancel) != DialogResult.OK)
cb.SelectedItem = selectedSomeObject;
else
{
selectedSomeObject = tem;
}
}

Categories

Resources