I have made a simple test application for the issue, two winforms each containing a button.
The button on the first form opens the other form when clicked. It also subscribes to keyup events.
The second form has its button set as "AcceptButton" and in the Clicked event we sleep for 1s and then set DialogResult to true (the sleep is to simulate some processing done)
When enter is used to close this second form the KeyUp event of the button on the first form is triggered, even though the key was released well before the second had passed so the second form was still shown and focused.
If any key other then enter is pressed in the second form the event is not triggered for the button on the first form.
First form:
public Form1()
{
InitializeComponent();
buttonForm2.KeyUp += new KeyEventHandler(cntKeyUp);
}
void cntKeyUp(object sender, KeyEventArgs e)
{
MessageBox.Show(e.KeyCode.ToString());
}
private void buttonForm2_Click(object sender, EventArgs e)
{
using (Form2 f = new Form2())
{
f.ShowDialog();
}
}
Second form:
private void button1_Click(object sender, EventArgs e)
{
Thread.Sleep(1000);
this.DialogResult = DialogResult.OK;
}
Does anyone know why the event is triggered for the button on the non active form and what can be done to stop this from happening?
You're making a blocking call, then closing the form, before the WM_KEYUP message is sent.
By the time the message is sent, the second form is gone, so currently focused control is on the first form.
You can solve this by calling BeginInvoke in the second form's click handler to only hide the form in the next message loop (after the KeyUp)
One way around:
You can verify in cntKeyUp if the sender is the Form that you expect then you process it, otherwise ignore.
Related
Ok, I have a question about the Form Controlbox. I was wondering if it is possible to change or add what the exit button does on the form.
I can easily minimize, maximize and exit the form no problem. But this is what I am facing.
My app has an access login. After you log in it comes to the main form. I have a log out button when pressed, it goes back to the login form.
However, if you press the exit button, it exits the main form, and the program is still running, but with no way to bring the login form up.
So what I am trying to do is, when the main form is exited through the red X I want it to go to the login.
I can go the complex route: borderless form, movable form, custom buttons and etc., etc.,
I think it would be easier to change or add the exit button to return to the login form. Is this possible?
Move the logic out of your button click event, into a separate method.
private void button1_Click(object sender, EventArgs e)
{
OverrideFormExit();
}
private void OverrideFormExit()
{
// execute the code that was previously in button1's click event
}
Now you can subscribe that same method to your Form's Closed event, so that it executes when the user closes the Form.
For example, place the following in your Form's constructor:
FormClosed += (s, e) => OverrideFormExit();
Alternatively, you can subscribe to the main Form's Closed event from within the Login Form, when you instantiate the main Form. I'm guessing at what your code looks like here, obviously.
private void ShowMainForm()
{
FormMain frmMain = new FormMain();
frmMain.Show();
frmMain.FormClosed += (s, e) => this.Show();
this.Hide();
}
Im making a little game that runs in real time. After you enter your name time starts it counts in seconds then minutes then hours. So i have it set up so that when they lets say you click on a button and it takes them to another form. In that form there are some buttons and depending on which one they press it SHOULD send a value back (number of hours) and add it to the current running time in form one automatically, when the form becomes visible again. I have a back button on form2 and i wanted it to add it after you click press it if thats possible!?
General the solution for passing data between forms is using events.
- Declare an event in form 2
- when declare form 2 in form 1 subscribe to event
- on event implementation make any operation that you want.
On other solution is to use a design pattern like Producer-Consumer.
You could use events as suggested by ctescu. Another option, if you can show the subforms as dialogs is simply to use the ShowDialog() method instead of the Show() method. This way you can in a simple manner get the propertyvalues after it has been closed.
private void button1_Click(object sender, EventArgs e)
{
frmSomeForm frm = new frmSomeForm();
frm.ShowDialog(this);
if (frm.DialogResult == System.Windows.Forms.DialogResult.OK)
{
//When the form is closed we can retrive values from it
int timeAdd = frm.UserSelection;
//Add number of hours to our property/field
}
//We are finished with the form -- dispose it
frm.Dispose();
}
All you need to add in the click-event of the "back-button" in the child form is setting the dialog result (When this property is set, the form will close)
private void btnBack_Click(object sender, EventArgs e)
{
this.DialogResult = System.Windows.Forms.DialogResult.OK;
}
I have a winform with a button that the user clicks when they want to generate a certain report. When this button is clicked, another winform opens up. The second winform has a text box and a button to take you back to the first winform.
When the second from opens up, I want the text box to already have the report displayed. Therefore, all the user has to do is is look at it and go back to the previous form when finished.
To do this, would I assign the text box to the appropriate method and put it in a Form1_Load event method?
I've never used the Form1_Load event method so I'm a little unsure if this is the proper way of doing it.
Yes, of course, in the Form_Load event you have access to all of your controls already Initialized by the form constructor via InitializeComponent().
Then you can call
private void Form_Load(object s, EventArgs e)
{
textBox1.Text = "your_report_title";
}
Yes, this would be the correct use of Form1_Load().
private void Form1_Load(object sender, EventArgs e)
{
textbox1.Text = "Whatever is supposed to go here"
}
Alternatively you can use the constructor of the form which should already be there.
public Form2(string text)
{
InitializeComponent();
textBox1.Text = text;
}
Then just open the form using
Form2 form2 = new Form2("text that should be displayed");
form2.Show();
I have this simple code, where when the user leaves the TextBox control, TreeView gets focused:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.treeView1.Nodes.Add("A");
this.treeView1.Nodes[0].Nodes.Add("A.A");
this.treeView1.Nodes.Add("B");
this.treeView1.Nodes[0].Nodes.Add("B.A");
}
private void textBox1_Leave(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Leave..");
this.treeView1.Focus();
}
}
If we execute this code the Leave event is fired twice:
Leave..
Leave..
But if we set focus to other control, only one Leave event is fired.
Is that a problem of the TreeView? Do you know any workaround? Should we report this to Microsoft?
Thanks,
RG
this.treeView1.Focus();
Do not use the Focus() method in an event handler that's called because of a focusing event, like Leave. If you need to prevent a focus change then use the Validating event instead. Setting e.Cancel = true stops it.
But do note that this isn't very logical to do so for a TreeView, there isn't anything the user can do to alter the state of the control. You'll trap the user. Maybe that was the intention, do make sure the user can still close the window. If not then you might need the FormClosing event to force e.Cancel back to false.
Given that there is no code there to wire up the event I'm guessing you did it from the designer which means a line of code such as
textBox1.Leave += new EventHandler(textBox1_Leave);
will have been added to the Form1.designer.cs, check this file to ensure the line doesn't exist more than once as for each time this line is run you will get an event trigger, so if you run the line 3 times the Leave event will fire 3 times when you leave the textbox!
HTH
OneShot
using c# winforms vs2008
I've got a textbox on a form with a method being called from the textBox1_Leave event. The method takes the contents of the textbox in question and populates other textboxes based on the contents.
My problem is that is the user has focus on the text box then clicks the button to close the form (calling this.close) then the form does not close because the textbox leave event gets fired.
If the textbox does not have focus on form close then the form closes fine.
If however a user closes the form by clicking the little X close icon in the top corner the it closes fine all the time with out the textbox leave event being fired.
How can I duplicate the X close functionality so that I can always close the form without the textbox leave event being fired?
The simplest solution is going to be to check which control is actually focused before doing your post-processing - but you can't do it in the Leave handler, because the focus will still be on the text box at that point.
Instead, you need to move your logic to the LostFocus event, which is not in the designer. You'll have to wire it up at runtime:
public class Form1 : Form
{
public Form1()
{
InitializeComponent();
textBox1.LostFocus += new EventHandler(textBox1_LostFocus);
}
private void textBox1_LostFocus(object sender, EventArgs e)
{
if (closeButton.Focused)
return;
// Update the other text boxes here
}
}
The LostFocus event happens to fire after the new control receives focus.
Clarification - you might find that it works by putting this logic in the Leave event - if the focus is changed by the mouse. If the keyboard is used instead, you'll get the wrong behaviour. LostFocus is reliable in both cases - the focused control will always be the "new" control. This is documented on MSDN: Order of Events in Windows Forms.
Incidentally, the reason why you're not having this problem with the "red X" is that the X is not actually a control that can receive focus, it's part of the window. When the user clicks that, it's not causing the text box to lose focus, and therefore isn't causing the Leave event to fire.
Another approach:
Use the textbox's validating event instead of it's leave event, then change the button's CausesValidation property to false. You will also have to set the textbox to not cause validation in the button's click event so the validating event will not fire when the form is closing (thanks to #Powerlord for pointing this out).
private void button1_Click(object sender, EventArgs e)
{
this.textBox1.CausesValidation = false;
this.Close();
}
You could also handle the FormClosing event and make sure the e.Cancel argument does not get set to true by the validating events on the other controls on the form. I think they will be fired off before the FormClosing event.
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = false;
return;
}
}
you can check to see which control has just got focus.
private void textBox1_Leave(object sender, EventArgs e)
{
if (btnClose.Focused)
return;
// go from here
}
Just check if the form owning the textbox is disposing? If it's getting closed, it's disposing. If it's disposing you could simply end the pesky 'leave' event without doing anything. I didn't check it and forgive me, I'm choked on a project of my own so and I was searching myself, so I don't think I'll have time for that.
private void GuiltyTextBox_Leave(object sender, EventArgs e) {
Form formOwningTheTextBox=(Form)((Control)sender).TopLevelControl;
if (formOwningTheTextBox.Disposing || formOwningTheTextBox.IsDisposed) return;
.......
}
I just believe this is going to work with minimum effort and wanted to send a quick answer before I resume searching my own answer.
Write Following line of code in text box leave event on top
if me.closing then
return
end if