Keep a button invisible until a RadioButton is clicked c# - c#

I'm trying to force the user to select a rabiobutton before being allowed to move next. I made the "Next" button invisible but I have like 10 radiobuttons that must be verified if any of them are checked. By definition, only 1 radiobutton can be checked. My code looks something like this:
b1.Text = "Next";
b1.Parent = fpn1;
fpn1.Controls.Add(b1);
b1.Dock = DockStyle.Bottom;
b1.BackColor = Color.LightGray;
b1.Visible = false;
RadioButton rb;
while (b1.Visible == false)
{
MessageBox.Show("LOOOL");
//Thread.Sleep(5000);
rb = fpn1.Controls.OfType<RadioButton>()
.FirstOrDefault(r => r.Checked);
if (rb != null)
{
b1.Visible = true;
}
}
So while none of my radiobuttons is clicked, b1 is invisible. The problem is... this going into an infinite loop. The user can't even pick any button anymore cause the page won't load. Any idea of a get-around?
What else can I do to have the wanted result?

Infinite loops are really good at blocking an application from doing anything. Essentially, you're thinking about it backwards. You're thinking:
Keep making the button invisible until something happens.
Why? Once you make the button invisible, it's going to stay that way until you change it. So, instead, think of it this way:
Make the button visible when something happens.
In this case "something happens" is a user changing the values of your radio buttons. So you want a handler for that event:
private void radioButton_CheckedChanged(Object sender, EventArgs e)
{
// your logic here
}
You can use the forms designer to assign this function to all of the CheckedChanged events of the various radio buttons, so they all use the same handler.
Then what would "your logic" be? Well, really, that's up to you. It sounds like you want to wait until several different radio button groupings have been selected? So you'd build some conditional based on that. At a high level, that would semantically look like this:
if (allRadioButtonsSelected())
b1.Visible = true;
If the line of code you have does what you want:
rb = fpn1.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Checked)
then you could even just use that:
if (fpn1.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Checked) != null)
b1.Visible = true;
Though it doesn't entirely sound like that's what you're looking for, since that's going to tell you if just one radio button is checked. But I may have misunderstood you on that, so it's up to you.
The point is, don't keep looping and blocking the thread while checking to see if something has happened. Because while you're blocking the thread, it will never happen. Instead, use event handlers to respond to events when they happen.

You are blocking the thread that's why it is not loading. I don't see a reason why you need a loop as when a user clicks a radio button you can raise an event. Then when you handle the event you set the visibility to true.

Related

C# windows forms handle click spam [duplicate]

This question already has answers here:
Is it possible to avoid multiple button clicks on a Winform?
(3 answers)
Closed 2 years ago.
I have an app with many user controls and many buttons on each, each button has an OnClick event which does some important stuff and then sends to a new user control.
The problem comes when the user clicks really fast multiple times, the event code gets executed more than once before exitting to a new user control, causing problems.
My current solution is to disable the button on the very first line of the event handler, but doing this to every window and handler would be troublesome, what can I do?
EDIT: Would it be a good solution to derive from Button, and override the OnClick event so it always does a check for a "working" variable, and if it is true, it doesnt start the event ? Something like:
public class MyButton : Button
{
private static bool isWorking = false;
protected override void OnClick(EventArgs e)
{
if (!isWorking)
{
isWorking = true;
base.OnClick(e);
isWorking = false;
}
//Else do nothing
}
}
You can use some timeStamp to delay between 2 clicks:
DateTime timeStamp;
//this will handle the clicks with the allowed interval being 0.5 second
//Note that a tick is equal to 1/10,000,000 of second.
private void click_Handler(object sender, EventArgs e) {
if ((DateTime.Now - timeStamp).Ticks < 5000000) return;
timeStamp = DateTime.Now;
//your code goes here ....
}
If you want all buttons to wait until one button's work is done, add a bool isProcessing variable to your form. Wrap the work of each button inside an if (!isProcessing), and set that flag to true in the first line inside the if statement. Then don't forget to set it back to false right before you exit the if.
I'm assuming you're doing all of this asynchronously, since if it's all in the same thread, the form will lock while it's processing the work. This will solve your issue though.
Disabling controls while sensitive operation is on-going is a typical solution that I always apply.
But since there can be quite a few controls on one screen that are affected by some click or change in UI, I typically design forms to have a specialized method which walks through all the affected controls and disables/enables them accordingly.
Something like this:
void EnableControls(bool enable)
{
foreach (Control ctl in this.Controls)
ctl.Enabled = enable;
}
Similarly, you could group controls into related buckets, so to disable/enable only one of them etc. Depends on your precise needs.
There is an alternative solution to use timer - disable the button, but enable it after 1 sec. This prevents nervous users from clicking multiple times if that would cause damage to data (i.e. each click is treated as a new operation).
I would call the same function from every button and then perform the specific task:
private void Button_Click(object sender, EventAgrs e)
{
Button btn = sender;
btn.disable = true;
switch (btn.AccessibleName)
// call specific function for the particular button or do it all here
}
I'm not sure if this would even work, but just an idea...
You could try with aspect oriented approach (with the help of Postsharp for example):
Create two aspects, one for method entry and one for method exit. In the method entry mark the current method as 'processing' (add the method name to a hash set for example). In the method exit mark the method as 'not processing' (remove it from the hash set). Then in the method entry check if the method is processing and if it is, then cancel the method (like this: https://stackoverflow.com/a/2437794/113858)
Mark all of your event handlers with this aspect.

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.

Bring cursor to a textbox in C#

I want to bring the cursor to a textbox when i clicked a button. How can i do that? I tried Focus() method but it didn't not work. The code is shown below.
CsNIPAddrTextBox.Focus();
CsNIPAddrTextBox.TabIndex = 1;
Try textbox1.select(). It's the best approach to bring your cursor to your textbox. It also selects content of the texbox which makes it easier for the user to edit what's inside the textbox.
If that's a 'proper' TextBox (i.e. not custom) then simply calling Focus() should work. It might not, however, if it's read-only (I'm not sure - I've not tried. I know you can get a caret in a read-only box, which implies it can get focus). Certainly if it's not Enabled then you won't be able to set focus.
Check the CanFocus property is true - if it's not, then there might be some other reason preventing the control from receiving focus.
If that's true, however, and the caret still doesn't make it to the control - you need to verify that it is receiving it. Add an event handler for the text box's GotFocus event and breakpoint it to clarify that it gets hit. My guess is that it your breakpoint will be hit. If so - then the answer is that another process is setting focus to another control immediately after your button click occurs. For example, if you do this kind of thing in a validation event handler you'll get a similar result, because the Windows Forms pipeline is already in the process of changing controls when the handler is fired.
Also - why are you setting TabIndex=1? Generally TabIndex is set at design time and left alone (unless of course these are dynamically created). Unless you have a particular reason for doing this I'd get rid of that line. It doesn't have a bearing on why this would/wouldn't work - just an observation.
Edit again:
If you try to select a TextBox in the Click event of a TreeView, it usually fails, because after the Click event the TreeNode will be selected, making your previous Focus() or Select() useless. The workable way is, perhaps, calling them in a Timer.
Timer t = new Timer();
t.Interval = 10;
t.Tick += new EventHandler((s,ev)=>textBox2.Focus());
t.Start();
This is more like a hack though...
Set theActiveControl property of the form
ActiveControl = yourtextbox
You have to use TextBox.Select Method
For example
textbox1.Select(textbox1.Text.Length,0);
Sets the cursor to the end of the text in yout textbox.
If i read right you are talking about moving mouse cursor to the textbox? - Then you can use code like this:
System.Windows.Forms.Cursor.Position =
PointToScreen(
new Point( textBox1.Location.X + 5, textBox1.Location.Y + 5)
);
I know many of you had provided answers, but this may be useful to some who weren't able to get from previous responses.
This worked for me, setting Select() on input text had set the cursor to the textbox.
Have this in form constructor:
this.Activated += OnActivated;
Handler Code:
private void OnActivated(object sender, EventArgs eventArgs)
{
txtUser.Select();
}
if textbox.Multiline=true and/or textbox.WordWrap = true, the cursor might be hiding at the bottom of the field.

C# .net Make checkboxes to behave as a radio button

I have a group box which has some radio buttons. I am trying to implement serialization with the help of a tutorial from Code Project. That tutorial supports serialization of checkboxes and not radio buttons. So i need to make the radio buttons in my app as checkboxes (that is they should be check boxes but work like a radiobutton).
I tried writing code, but what happens is when I find that a particular checkbox is checked and I go to uncheck or vice versa, it triggers that checked_changed event handler and this goes into an infinite loop.
Can someone help me out with this?
Thanks
UPDATE:
After seeing your replies, I would like to say thanks a lot. Yes, You are all right that we should not be messing with the basic properties. I will work with changing the serialization method.
P.S The link for the tutorial is http://www.codeproject.com/KB/dialog/SavingTheStateOfAForm.aspx
Final Update:
After following the replies posted here, I decided not to change the default properties but to change the serializer code. I did that and it now works perfectly. Thanks a lot, everyone.
I agree with all the commenters: do not make checkboxes that act like radio buttons, it flies in the face of UI conventions and confuses users.
The right way to do this is to fix your code to serialize the radio buttons, but without seeing your code it's hard to know how to help you. For a start, you can fix the CheckedChanged looping by temporarily removing the event handler before you do anything. For example:
myCheckBox.CheckedChanged -= MyCheckedChangedEventHandler;
myCheckBox.Checked = true;
myCheckBox.CheckedChanged += MyCheckedChangedEventHandler;
If this alone doesn't fix your issue, please show us your code and we'll try to help more.
Edit: Based on the tutorial listed in your update, I'm guessing the problem happens when you call FormSerialisor.Deserialise(), which triggers your controls' event handlers to fire? If that's the case, the quick fix is to just do what I mentioned: remove the radio button event handlers before calling FormSerialisor.Deserialise() and then re-add them afterwards. Example:
myRadioButton.CheckedChanged -= MyCheckedChangedEventHandler;
FormSerialisor.Deserialise(this, mySerialisepath);
myRadioButton.CheckedChanged += MyCheckedChangedEventHandler;
You may also need to edit the FormSerialisor class to handle RadioButtons; just copy the code that handles checkboxes but change all the references to RadioButton. It's not clear from your question whether this step will be necessary or not.
Like the comments say, you're better of getting serialisation to work with radio buttons than messing around with checkboxes. Having said that, to get the effect you need, just set a variable that indicates you're already handling a change event, and test for it. Something like this (it's terrible code, but demonstrates the idea):
private bool autoChange = false;
private void ChangeHandler() {
if (!autoChange) {
autoChange = true;
/* Do stuff */
autoChange = false;
}
}
Unregister from the Checkedevent (by using -=) before doing that. And re-register after you're done.
(I'm not arguing with the comments. Just answering the question.)
Hello, here a simple ansewer to transform the CheckBox to a RadioButton:
object clickBox = null;
private void checkBox_Click(object sender, EventArgs e)
{
clickBox = sender;
foreach (Control c in this.Controls)
{
if (c is CheckBox)
{
if (c != clickBox)
{
((CheckBox)c).Checked = false;
}
}
}
And add this Click event o every Checkbox
Finish
Take the CheckedListBox and call ItemCheck Event and use below code It will behave like Radio buttons (It works for me):-
private void chkListBox_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (e.NewValue == CheckState.Checked)
{
for (int item = 0; item < chkListBox.Items.Count; item++)
{
chkListBox.SetItemChecked(item, false);
}
}
}

How to force control to fire leave event in winforms using c#?

I am pasting text in textbox1.text and I need textbox1 should fire its leave event by itself.
For now I am using this following code. but i will appreciate if anyone can suggest me an elegant or better way:-
private void event()
{
textbox1.Text = SearchedText;
textbox1.Focus();
textbox2.Focus();
}
First I am pasting text, then setting up Focus on the control, then set up focus again on second control. It is firing leave event of textbox1, but any thing better?
Just call the code directly, no need to wait for an event:
private void textBox1_Leave(object sender, EventArgs e) {
mumble();
}
private void someEvent() {
textBox1.Text = SearchedText;
mumble();
}
void mumble() {
// etc...
}
Just calling textBox1_Leave(this, EventArgs.Empty) works fine too.
You should handle the TextChanged or Validated events instead of the Leave event.
To FORCE Leave, Validating and so on Events, no matter what, I've found ONE working solution.
First i tried:
ProcessTabStop(true);
ProcessTabStop(false);
instead of:
textbox1.Focus();
textbox2.Focus();
Problem with the TextBox 1 and 2 Focus() is that its only Active Component that needs Leave, Validating and so on fired, not other Controls, and besides, what if the form is dynamic, you as a programmer not necessarily have any idea what Control you are trying to Leave, that's why i changed Control.Focus() method to ProcessTabStop method above. The problem is then, if only ONE Control has TabStop true, there is no control to go to and back from. So Events are NOT Fired.
Next problem is that i not necessarily Close the Form with the mouse so Focus doesn't change, I use a Key (Ctrl+Enter) to Accept the Form, and then Leave, validating and so on are NOT fired, when i Send Form Close, as Form Close registers weather there are changes or not. But Values are set in Leave on TextBoxes, so I had to find a solution that worked no matter what i did to it. I almost gave up, actually i had a problem report all filled out, when I thought, what if i set ActiveControl to Null and then to the Control it came from. It worked, but had som "Flicker" due to color change on Parent Panel depending on Active or Inactive.
The "Workaround" that works in all cases is:
Control Old = ActiveControl;
// ActiveControl.SuspendLayout();
// ActiveControl.FindForm().SuspendLayout();
ActiveControl = null;
ActiveControl = Old;
// ActiveControl.FindForm().ResumeLayout();
// ActiveControl.ResumeLayout();
That seems to fire Leave, Validating and so on Events, no matter number of Form Controls and TabStopped Controls. You MAY need to SuspendLayout on either ActiveControl, or Form. My Control (Parent Panel) changes color when Active/Inactive, if I do not Suspend Layout on Form, parent panel gets an unwanted "flicker" effect.
Looking at the solution, it is very obvious, now I've found it, but took me half a day to try different things that solved one or another problem, but not all.
I know this a VERY old thread, but one of very few articles I've found on the subject of Forcing Leave Event to be Fired.

Categories

Resources