Calling a KeyDown Event on Form Load - c#

I would want to launch a KeyDown Event on Form_Load however its taking me somewhere else in the Form_Load event.
Form_Load:
int static_int = 0;
private void Form1_Load(object sender, EventArgs e)
{
if(condition == true)
{
txtInput.Text = "something";
txtInput.Focus();
SendKeys.Send("{Enter}");
int somegeneratednubmer = 20;
static_int = static_int + somegeneratednumber;
//somemore code here
}
}
KeyDown:
private void txtInput_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Enter)
{
static_int = 10;
//somemore codes here too
}
I would like to get the SUM of static_int and somegeneratednumber which is 30. However, after Debugging, I'm getting its initialized value of 0. From what I understood, after SendKeys.Send("{Enter}") the KeyDown event should proceed.
Why is it not??
How would I get the correct result? I really should do the KeyDown event on Form_Load, a conditional event...
or What am I doing wrong here?
Note: originally static_int is initialized on a Class

No, the KeyDown even will proceed at the earliest possible moment, which is when the appropriate message is executed from the form's message queue. That cannot happen before the Load event finishes, because that also on the message queue. Even if that weren't the case, SendKeys doesn't wait for the action to be processed. It just sends the message and returns immediately.
Another problem is that SendKeys sends the virtual keys to the currently active window. That can never be your window, since your window isn't even shown yet! When something behaves weird, a good first step is to read the documentation.
So, why is the value of static_int zero, instead of 20 or 30? Well, the likeliest case is an unhandled exception, and I'm pretty sure that's exactly what happens when you do tbxInput.Focus. The control doesn't quite exist yet, and it can't be made the input focus. If you have trouble understanding all this, you might want to find some book on the basics of how Windows windows work - there's nothing .NET can do about it, and it's places like this where the (very pretty) .NET abstraction leaks a lot. If you're planning to do any Windows UI development, you really need to know at least the basics.
However, that's completely unnecessary anyway. You don't have to execute a KeyDown event. Just make a method that's called from both the Load event handler and the KeyDown event handler.

try adding this event instead
Form1 isn't loaded yet so no events yet.
private void Form1_Shown(Object sender, EventArgs e)
{
SendKeys.Send("{Enter}");
}
But truly this design is wrong

Related

How do I prevent any button click events from queuing until the event handle is finished with the first call

I want to prevent a button click from queuing. In testing I have a Form, a Button and in the Code-Behind I have the event handler:
private void button1_Click(object sender, EventArgs e)
{
if (_codeRunning)
return;
_codeRunning = true;
//Application.DoEvents();
//button1.Enabled = false;
_click ++;
Debug.WriteLine("Click Number: " + _click);
Task.Delay(5000).Wait();
//button1.Enabled = true;
_codeRunning = false;
}
When I run debug and click the button twice or three or four times rapidly, Debug Output shows each click about five seconds after the last one. What I would like it to show is a single Click and drop the rest until first Event is complete.
I have also tried to disable the button, as well as temporarily remove the Handler from the Button_click event. It is all the same results.
There are various amounts of trouble you'll get into when you hang-up the UI thread like this. This is certainly one of them, nothing pleasant happens when the user wildly bangs on the button to try to get something noticeable to happen. And sure, those clicks won't get lost, they stay stored in the message queue. To activate your Click event handler again when your event handler stops running.
Pretty important to learn how to use the BackgroundWorker or Task classes to avoid this kind of trouble. Just setting the button's Enabled property is then enough to solve this problem.
Purging the mouse clicks from the message queue is technically possible. But ugly to do, it requires pinvoke. I'll hesitantly post the alternative, don't assume that this is in general a good strategy. You'll need to read this post to have some insight into why DoEvents() is a dangerous method.
private void button1_Click(object sender, EventArgs e) {
button1.Enabled = false;
button1.Update();
'' long running code
''...
Application.DoEvents();
if (!button1.IsDisposed) button1.Enabled = true;
}
The Update() call ensures that the user gets the feedback he needs to know that banging the button repeatedly isn't going to do anything useful. The DoEvents() call will dispatch all the queued-up mouse clicks, nothing happens with them since the button is still disabled. The IsDisposed test is essential to solve the problem with DoEvents(), it ensures your program won't crash when the user clicked the window's Close button while the code was running.
Use the HourGlass class in this post to provide more feedback.
I had a button that on click event was going to run a method. Same issue happent and when the user clicked multiple times the method was triggered multiple times. So I made a boolean and changed it value when the method started.
private bool IsTaskRunning = false;
private void MyMethod()
{
if ( IsTaskRunning==false )
{
IsTaskRunning=true;
// My heavy duty code that takes a long time
IsTaskRunning=false; // When method is finished
}
}
So now the method runs only if it's done the last time.

Assign Form1_Closing method to Form Closing Event

I have the following method defined to be called when a form closes
private void TimeKeeper_Closing(object sender, EventArgs e)
However, it doesn't show up in the list when I try to assign it in the Events section of the Form properties. Is there something I need to do to get it to show up there?
EDIT: Sorry, originally posted the wrong method...
The Closing event is obsolete, it dates from .NET 1.x. Microsoft goofed that one pretty badly and it was replaced in .NET 2.0 with the FormClosing event. Which tells you a lot more about why the form is getting closed. The e.CloseReason is very important, you don't want to prevent Windows from shutting down.
Which is why you can't find it, you are not supposed to use it anymore. Note how the answer you accepted just stops your program from compiling. You probably discovered the FormClosing event by yourself.
Might as well go whole-hog and point out how silly it is for a class to listen to its own events. Events are meant for other code. They work pretty well in the designer, that's why you end up writing code like this. But the sane thing to do is to just override the method:
protected override void OnFormClosing(FormClosingEventArgs e) {
if (e.CloseReason == CloseReason.UserClosing) {
// Some code that might set e.Cancel = true
//...
}
base.OnFormClosing(e);
}
Which has many advantages, beyond the typical lossage of forgetting to subscribe the event with the designer, a derived class can simple alter the decision being made here by setting e.Cancel back to true.
You have to change EventArgs to FormClosingEventArgs
private void TimeKeeper_Closing(object sender, FormClosingEventArgs e)

Disabling a Textbox Using TextChanged Event

The form I am using requires a copy pasted URL. I am trying to have a textChanged event that will check the url as soon as it is pasted, telling the user whether it is valid or invalid. I also want to be able to lock out the textbox when this happens, with a message saying something like "Processing...".
The problem is with the code below, the textbox is never disabled, the program will do the checkUrl() method and the textbox is never disabled even though it is first to execute (I assume it is but the fact there is a function call right underneath it is messing around with something or getting higher priority).
How do I go about making the control visually disabled while the method runs?
private void urlTxtBx_TextChanged(object sender, EventArgs e)
{
urlTxtBx.Enabled = false;
checkUrl();
urlTxtBx.Enabled = true;
}
I think this is happening because the Application needs to complete all the active threads before disabling the TextBox. Please try the following code:
private void urlTxtBx_TextChanged(object sender, EventArgs e)
{
urlTxtBx.Enabled = false;
Application.DoEvents();
checkUrl();
urlTxtBx.Enabled = true;
}
This will let the UI to be updated. For more details check here.

How to handle the user changing his mind without boolean flags?

I have a NumericUpDown in my application but it is dangerous. When the value is changed the entire document is erased. Because of this, I'd like to give the user a warning (even if he accidentally hits OK he can undo it.)
The problem is that it seems that the only event I could handle would be the ValueChanged event and I'd end up with code like this.
private bool ignoreValueChanged = false;
private void numFoobar_ValueChanged(object sender, EventArgs e)
{
if (ignoreValueChanged)
{
ignoreValueChanged = false;
return;
}
if (MessageBox.Show("This will erase the entire document. Are you sure?", "Confirmation", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
{
ignoreValueChanged = true;
numFoobar.Value = oldValue; // The ValueChanged event gets called again =/
return;
}
// More code
}
There has got to be a better way. I was hoping Validating would help but it is only called when closing the form it seems.
Oh well you could remove the event subscribed to the numericUpdown control before resetting its value, after resetting it then again subscribe it back. This way, the event is not called when you reset the value.
But i am also thinking about how to check if the event is already subscribed or not. But above said method shall give you half the solution.
Here i tried this a bit and it seems to work but i cant seem to figure out how to check if already that same event is subscribed or not.
void NumericUpDown1ValueChanged(object sender, EventArgs e)
{
if(numericUpDown1.Value > 10)
{numericUpDown1.ValueChanged -= new System.EventHandler(this.NumericUpDown1ValueChanged);
numericUpDown1.Text = "5";
}
else numericUpDown1.ValueChanged += NumericUpDown1ValueChanged;//Here i need to first check if already it is subscribed or not before such that i dont want to subscribe double time
}
Did some Googling, and here's something that might work:
private void numFoobar_ValueChanged(object sender, EventArgs e)
{
this.ValidateChildren();
}
private void numFoobar_Validating(object sender, CancelEventArgs e)
{
if (MessageBox.Show("This will erase the entire document. Are you sure?", "Confirmation", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
{
e.Cancel = true;
}
}
Note that you'll need to reset the value as canceling the validation doesn't change the value. But this is the only way I was able to get the Validating event to fire.
ContainerControl.ValidateChildren Method
There are couple of issues to work out with this, however:
When exiting the program, it will fire the Validating event again; probably need to handle it in one of the closing events for the form or application.
I played with resetting the value in the ValueChanged event, but that trigged the Validating event again.
I'll keep playing with it for a bit and see if I can come up with a more solid solution for you.
This is really a usability issue. I guess what you are trying to do is to ignore the valueChanged event when the value has changed to the current persistent value. One option is to compare with the current value the document is based on.
Been googling a bit. First, I came up with this:
typeof(NumericUpDown).GetField("currentValue", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(numericUpDown1, 5m);
Which works but it is reflection and it seems a little over the top so I decided against it. Then I found this:
C# winforms numericupdown control
And based my solution on the second answer, which isn't so bad to be honest.

Triggering an event after a Winform layout is complete

I am working on a C# WinForm application.
I want to trigger some processing once the form has been "shown" and the layout of the form is complete.
I am using the "_Shown" event, but this seems to trigger before the layout of the form has completed. Is there event I can use that fires once the layout is complete?
Put Application.DoEvents() at the start of the form's Shown event handler. This will force all the controls to be rendered.
I don't see an event after Shown you can use for this purpose. Could you not use a timer to delay your processing in the Shown event?
An old trick in VB6 used to be to use the Paint event:
bool firstShown = false;
void form_Paint(Object sender, EventArgs e) {
if ( !firstShown ) {
YourMethodThatNeedsToRunOnShown();
firstShown = true;
}
//the rest of your paint method (if any)
}
It is a little hacky, but it does work
This works for me and is much less "hacky" than other suggestions:
protected override void OnLayout(LayoutEventArgs levent)
{
base.OnLayout(levent);
if(someControl == null)
return; // be careful of OnLayout being called multiple times
// otherwise, do some stuff here, set control sizes, etc.
}
AS far as I can remember the event order is something like
Form.Load
Form.Layout
Form.VisibleChanged
Form.GotFocus
Form.Activated
Form.Shown
So if something is still happening after Form.Show it's because of the way you coded it.
Are you maybe creating the form dynamically?
The best solution is the Shown() event: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.shown.aspx
"The Shown event is only raised the first time a form is displayed; subsequently minimizing, maximizing, restoring, hiding, showing, or invalidating and repainting will not raise this event."
Try using Form.GotFocus (inherited from control)..
something like this.
private void Form1_Load(object sender, EventArgs e)
{
this.GotFocus += new EventHandler(Form1_gotFocus);
this.Focus();
}
private void Form1_gotFocus(object sender, EventArgs e)
{
// You will need to Switch focus from form at the end of this function,
//to make sure it doesnt keep Firing.
}
According To msdn , the following happens:
When you change the focus by using the keyboard (TAB, SHIFT+TAB, and so on), by calling the Select or SelectNextControl methods, or by setting the ContainerControl..::.ActiveControl property to the current form, focus events occur in the following order:
Enter
GotFocus
Leave
Validating
Validated
LostFocus

Categories

Resources