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;
}
Related
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();
}
I have added a keyPress event on a ListView. With a breakpoint on my event, I can see that most of the keys trigger the event. However, a few among which, the one I'm interested in (delete), just won't trigger my event.
Is that weird ? And no, there's no broken keys on my keyboard :D
private void listView1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Delete)
{
ListView target = (ListView)sender;
if (target.SelectedIndices != null && target.SelectedIndices.Count > 0)
{
string ric = target.SelectedItems[0].SubItems[0].Text;
//target.Items.RemoveAt(target.SelectedIndices[0]);
ListModels.getInstance().getModel("Vols").removeRic(ric);
}
}
}
The reason for this is that the KeyPress event sends a character to the control based upon the character-key you press. However, as you'd expect, the delete key does not represent a character and is thus a non-character key.
Therefore using the KeyPress event will do nothing as you have noticed. You should use the KeyDown or KeyUp Events, either of which will work absolutely fine. The nuance being whether you want your event to fire upon pressing, or letting go of a key.
You'll want to use the KeyDown event for this.
In KeyDown use the condition as follows,
if (e.KeyCode == Keys.Delete)
{
// Your Logic....
}
Use keyDown instead; keyPress is something like a full keyDown + keyUp
The problem is that if you set EditMode property to EditOnEnter it won't fire. If you use EditOnKeyStrokeOfF2 it will fire the event
If you are looking for a solution where the user should only be able to choose from the defined items, then I believe you can do it with this:
private void DropDownRank_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = true;
}
See this code:
private void Form1_Load(object sender, EventArgs e)
{
listView1.KeyUp += new KeyEventHandler(ListView_KeyUp);
}
/// <summary>鍵盤觸發 ListView 清單</summary>
private void ListView_KeyUp(object sender, KeyEventArgs e)
{
ListView ListViewControl = sender as ListView;
if (e.KeyCode == Keys.Delete)
{
foreach (ListViewItem eachItem in ListViewControl.SelectedItems)
{
ListViewControl.Items.Remove(eachItem);
}
}
}
I tried all the stuff mentioned above but nothing worked for me, so im posting what i actually did and worked, in the hopes of helping others with the same problem as me:
Add an event handler in the constructor:
public partial class Test
{
public Test()
{
this.RemoveHandler(KeyDownEvent, new KeyEventHandler(Test_KeyDown));
// im not sure if the above line is needed (or if the GC takes care of it
// anyway) , im adding it just to be safe
this.AddHandler(KeyDownEvent, new KeyEventHandler(Test_KeyDown), true);
InitializeComponent();
}
//....
private void Test_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Delete)
{
//your logic
}
}
}
I'm a beginner with C# and I'm developing a basic application.
I want to check if the value of a textbox is a number with the following code :
private void check_value(object sender)
{
TextBox tb = (TextBox)sender ;
if (!Utility.isNumeric(tb.Text)){
MessageBox.Show(tb.Text.Length.ToString());
tb.Focus();
}
}
private void Amount_1_LostFocus(object sender, RoutedEventArgs e)
{
check_value(sender);
}
When I enter a letter in the textbox there is an infinite loop and it seems that the tb.Focus() actually cause the LostFocus event to be call recursively.
I don't understand why the call to the Focus method of an object triggers the LostFocus event of the same object.
Opening the modal MessageBox is responsible for loosing the focus. Try hook to Validating event.
As i said before in the link provided by Xaqron it's said that it's forbidden to use the Focus method in the LostFocus event.
And as I'm developing a WPF application there is no Validating event and CausesValidation property, so the others ways to validate the content is to use the TextChanged event or use binding validation.
Thank you for your answers.
Of course, in a perfectly valid program, you should not change Focus in the LostFocus event. This also applies to the Enter, GotFocus, Leave, Validating and Validated events, which Ms makes clear in the documentation https://learn.microsoft.com/pl-pl/dotnet/api/system.windows.forms.control.lostfocus.
However, in very unusual cases, you can use the timer to trigger changes to the Focus, bypassing this problem.
private TextBox tb = null;
private System.Windows.Forms.Timer MyTimer;
private void initialize()
{
MyTimer.Tick += new System.EventHandler(MyTimer_Tick);
MyTimer.Enable = false;
MyTimer.Interval = 100;
}
private void check_value(object sender)
{
tb = (TextBox)sender ;
if (!Utility.isNumeric(tb.Text)){
MessageBox.Show(tb.Text.Length.ToString());
MyTimer.Enable = true;
}
}
private void Amount_1_LostFocus(object sender, RoutedEventArgs e)
{
check_value(sender);
}
private void MyTimer_Tick(object sender, EventArgs e)
{
MyTimer.Enabled = false;
if (tb!=null) tb.Focus();
}
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);
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;
}
}
}