When I show a MessageBox with helpFilePath set to some url, the url loads multiple times. It seems to me that the url loads a number of times equal to the number of my forms parents plus one.
Can anyone explain why this is happening?
According to MSDN the HelpRequested event will fire on the active form:
When the user clicks Help button, the Help file specified in the
helpFilePath parameter is opened. The form that owns the message box
(or the active form) also receives the HelpRequested event.
The helpFilePath parameter can be of the form C:\path\sample.chm
or /folder/file.htm.
But I don't understand why raising the HelpRequested event on the parent forms should load the link from the child forms MessageBox.
Am I doing something I'm not supposed to?
This code will reproduce the behaviour:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// First button spawns new instances of the form
var button1 = new Button { Text = "New Form" };
Controls.Add(button1);
button1.Click += delegate
{
using (var form = new Form1())
form.ShowDialog();
};
// Second button shows the MessageBox with the help-button
var button2 = new Button { Text = "Dialog", Left = button1.Right };
Controls.Add(button2);
button2.Click += delegate
{
MessageBox.Show(
"Press Help",
"Caption",
MessageBoxButtons.OK,
MessageBoxIcon.None,
MessageBoxDefaultButton.Button1,
0, // Default MessageBoxOption (probably not related to the behaviour)
"http://SomeHelpSite.com/MyOnlineHelp.htm");
};
}
}
Click "New Form" a couple of times:
Then click "Dialog":
Now, click the help-button:
On my computer this opens SomeHelpSite.com tree times:
I have found a way to block the undesidered behavior and, probably, an explanation why this happens.
To block the opening of undesidered url after the first one you need to simply add an handler for the HelpRequested event. In this event you should inform the WinForms engine that you have handled the help request and no further action is required
public Form1()
{
InitializeComponent();
this.HelpRequested += onHelpRequested;
.....
}
protected void onHelpRequested(object sender, HelpEventArgs e)
{
e.Handled = true;
}
In this way, only one page is opened.
Now the explanation why this happens is, probably, reported at the MSDN page for the Handled property of the HelpEventArgs where you could find this statement:
If you do not set this property to true the event will be passed to
Windows for additional processing.
EDIT Further tests shows that also without setting the Handled property to true, the simple fact that an event handler for the HelpRequested event exists stops the undesidered behavior
Related
I am currently making an rpg using Winforms for a school project. However my knowledge on classes is so limited that I'm having trouble making a proper class that takes in data from 1 form, is used in the second form, then sent back to the first form.
The process I'm trying to accomplish is like this:
main form opens a second form that displays items in a listbox.
1
when you select an item and press a button to use it, the items effects are applied.
2
The data for the effect is in the first form where many other calculations are made with the same data.
3
I keep running into the problem of making a new object of a class and the data from the first form is reset. How would I go about either using an existing object from the first form, or creating a reference class maybe?
This is the function I want to run on the first form when the button on the second form is clicked.
public void SmallPot()
{
currentPHP += pHP * .25;
if (newPHP > pHP)
{
newPHP = pHP;
}
pHPBarUpdate = (int)(newPHP / pHP * 377);
pnlCurrentPHP.Width = pHPBarUpdate;
newPHP = currentPHP;
}
Expected:
When I click the use button on the popup form it closes and the items effects are displayed on the Main form.
What Happens:
Since I create a new object of form one in form two, all my variables are reset to 0 before the calculation, resulting in nothing happening after the second form closes.
I will give you a general guideline to implement a solution based on event definition and raising
Let's start from your second form where you need to communicate to the first form the event
public class Form2 : Form
{
// start creating the delegate type
public delegate void OnItemSelected(string itemName);
// declare the public event that this form will raise
public event OnItemSelected ItemSelected;
protected void cmdItemUse_Click(object sender, EventArgs e)
{
// When the user clicks to select an item....
string itemName = GetItemSelectedFromList();
// Check if someone is interested in this item selection
if(ItemSelected != null)
ItemSelected.Invoke(itemName);
}
}
Now we change something in the first Form. We need to create the second form and before displaying it we subscribe to the event exposed by the second form
public class Form1 : Form
{
... other stuff....
protected void cmdOpenSelection_Click(object sender, EventArgs e)
{
using(Form2 frm = new Form2())
{
// Subscribe the event giving it a method inside this class
// that doesn't return anything and receives a string
// as required by the delegate type of the event
frm.ItemSelected += handleItemSelection;
frm.ShowDialog(); // frm.Show();
}
}
private void handlerItemSelection(string itemName)
{
// This method is a custom Event handler and inside Form1
// will be called by Form2 through the Invoke on the event variable
}
}
In the example above I choose to pass a simple string, but of course you could pass anything including a reference type like an instance of a class containing all the info
required by the Item selection.
I have mainVariable.cs that contains delegates for events. Also I have several forms and a worker.cs. My problem is that Login form is starting form and handles some event. After that it hides itself and shows another form. Now the problem starts here, because second form which started after login, cant handle any events. I mean when I raise an event from worker.cs and login form handles the event not the second from even if I dispose the login form. How can I solve this puzzle ?
Apply this to your Programm.cs
Application.Run(loginForm);
if (loginForm.IsLoggedIn == true)
{
ERS_FDData.ERSUser user = loginForm.user;
loginForm.Close();
Application.Run(new frmMain(loginForm.user));
}
else
Application.Exit();
After the login is done, you need to set the Mainf Frame to be the application default window
For any event to be handled you need to assign it a subroutine.
You can do this from any form, given you initialize and show it first.
For example.
Form1
{
FormLoad()
{
mybutton.click += new EventHandler(myfunction);
}
myfunction(object o, EventArgs e) { // Dostuff }
}
So you'd initialize Form1 something like this
Form1 myform = new Form1();
And the event will work as the form expects.
Is there any way to have a messagebox immediately pop up when a form opens? I just want to display a short message about how to use the form when it opens. I tried
private void myForm_Load(object sender, EventArgs e)
{
DialogResult dialogOpen = MessageBox.Show("Use the navigation menu to get started.", "Welcome!", MessageBoxButtons.OK);
}
but it doesn't work.
Showing a MessageBox during Form_Load works just fine for me. I literally copy/pasted the code from your original post, and it worked. I'm on .NET Framework 4.5 on Windows 8.1.
Are you sure your Load event handler is getting called? Perhaps the it's not hooked up to the Load event properly.
I don't see why it wouldn't work in Form_Load. Definitely try doing as others have pointed out by putting it beneath form initialization.
Though, given that you're just showing a message box, I don't think there is any reason to store the result, so a simple MessageBox.Show(message); Should do the trick.
As #s.m. said, from a UX point of view, having a notification thrown in your face as soon as the app starts would be very obnoxious, at least if you have it EVERY time. Personally, I would create a boolean Settings variable, set it to true the first time the message is displayed, and only display it when the setting is false, i.e. the first time the message is displayed.
private boolean splashShown = Properties.Settings.Default.splashShown;
private void Form_Load(object sender, EventArgs e)
{
if (!splashShown)
{
MessageBox.Show("message");
myForm.Properties.Settings.Default.splashShown = true;
myForm.Properties.Settings.Default.Save();
}
}
And set up the splashShown Setting in your form properties.
If the problem is that your Form_Load() method isn't actually attached to your Form.Load() event, you can double click the form window in the designer and it will automatically created the Form_Load() base method for you and attach it to the Form.Load() event
Is there a reason to use the Load method of the form? If not you could to it in the constructor of form. If you want it to show up immediately after your form loads, you should do it in the constructor after the form is initialized. It should look something like this:
public partial class myForm : Form
{
public myForm()
{
InitializeComponent();
DialogResult dialogOpen = MessageBox.Show("Use the navigation menu to get started.", "Welcome!", MessageBoxButtons.OK);
}
}
The constructor (public myForm()) and the InitializeComponent(); should be automatically added to the form by Visual Studio after creating it.
Form_Load event occurs before the form is really visible.
I use:
static private bool splashShown = false;
private void Form1_Activated(object sender, System.EventArgs e)
{
if (!splashShown)
{
MessageBox.Show("message");
splashShown = true;
}
}
I have used this and it works fine. App start brings up messagebox first before all else.
InitializeComponent();
MessageBox.Show("put your message here");
This is a winform C# question. I have a textbox with a validating event listener to validate the content of the textbox against a regular expression.
After the validation, if entered value is not proper,i am showing the messagebox and i am cancelling the event so that mouse cursor move back to the textbox which has improper value.
This is working fine when i move out from that textbox to other buttons/textboxes.
But when i enter improper value and close the form (with the close button on right top corner), it validates the textbox contents and throws up the messagebox and form doesnot close as i am cacelling the event.
The problem is, when I click the X button on the right top corner of the form, I don't want the validation to be fired because I am closing the form anyway. How can I do this?
I will post the code snippet as soon as possible.
To use validating handlers such as the 'txtIPAddress_Validating()' handler below while being able to close the form without having to enter valid entries to do so, I do the following:
1) Initate validating handlers:
From the control properties of the control you wish to activate validation for, double click the 'Validating' event from this control event list. A control event list is accessed by clicking this control's property sheet’s event (lightning looking) toolbar button. You can then enter the code in the automatically generated handler with a name combining both the name of the control and '_Validating'. The part of this handler where something is established as invalid can force valid entries by adding the 'e.Cancel = true' instruction.
For such validating method examples, See 'txtIPAddress_Validating()' and 'txtMaskBits_Validating()' code below. Do not get distracted by the complete validation mechanism of these specific examples. All you need to see and reproduce in your own code in order to force validation is to add the 'e.Cancel = true' instruction at the right place of your own validating method. That is when the value is identified to be invalid.
At this point the validation should work fine but any attempt to close the form will trigger validation which will stop and insist for valid values before being able to close the form. This is not always what you want. When it is not so, I continue with the following.
2) 'Cancel' button that also cancels (disables) all validations:
a) Place a regular 'Cancel' button on the form which is associated to a method such as the 'btnCancel_Click()' method below.
b) Before the regular 'this.close();' instruction, add the 'AutoValidate = AutoValidate.Disable;' instruction. This instruction disables all 'validating' triggers. Note that the 'btnCancel_Click' event is triggered before any validation is taking place. That is not so for the Form Closing events that will all execute after validating events. That is why that validation cannot be disabled from any of these Form Closing events.
c) For this 'Cancel' button to work correctly, you also need to set the 'CausesValidation' property of this 'Cancel' button to 'false'. This is necessary, otherwise clicking on this button will trigger the validation before validating can be disabled by the above 'AutoValidate = AutoValidate.Disable;' instruction.
At this point, you should be able to quit by clicking on the 'Cancel' button without having to first enter valid values. However, clicking the upper right "X" button of the form's window will still force validation.
3) Make the upper right "X" button also cancel validation:
The challenge here is to trap such "X" clicked event before validation is executed. Any attempt to do so through a Form Closing handler will not work because it is then too late once execution reaches such handler. However, the click of the "X" button can be captured promptly via overriding the WndProc() method and testing for a 'm.Msg == 0x10' condition. When that condition is true, the previously introduced 'AutoValidate = AutoValidate.Disable;' instruction can again be used to disable overall validation in that case as well. See the WndProc() method below for a code sample of such method. You should be able to copy and paste that method as is in your form's class.
At this point, both the 'Cancel' an "X" buttons should cancel valdations. However, the escape key that can be used to close a form does not. Such escape key is activated when the form's 'CancelButton' property is used to link this escape key to the form's 'Cancel' button.
4) Make the escape key also cancel validation:
Similar to the "X" button, the escape key can be captured by overriding an existingmethod. That is the ProcessDialogKey() method. One more time, the previously introduced 'AutoValidate = AutoValidate.Disable;' instruction can be used to disable overall validation for the escape key as well. See the ‘ProcessDialogKey()’ overridden method in the code below to see how this can be done. Here again, you should be able to copy and paste that method as is in your own form's class.
At this point you should be done!
Further considerations:
It is good to notice that the following two other ways to close the window should also work fine at this point. These two ways are:
The 'Close' option of the upper left window icon button.
Pressing Alt+F4 which triggers the same closing action as the above 'Close' option.
These two ways of closing the window started to also cancel validation once you introduced the "X" button capture mechanism described in point 3 above.
That is it for me for this so far. Hoping this helps!
My code sample below:
public partial class frmMyIP : Form
{
public frmMyIP()
{
InitializeComponent();
}
// To capture the Upper right "X" click
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x10) // The upper right "X" was clicked
{
AutoValidate = AutoValidate.Disable; //Deactivate all validations
}
base.WndProc(ref m);
}
// To capture the "Esc" key
protected override bool ProcessDialogKey(Keys keyData)
{
if (keyData == Keys.Escape)
{
AutoValidate = AutoValidate.Disable;
btnCancel.PerformClick();
return true;
}
return base.ProcessDialogKey(keyData);
}
public bool IsValidIP(string ipaddr)
{
string pattern = #"^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"+
#"(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$";
Regex check = new Regex(pattern);
bool valid = false;
if (ipaddr == "")
{
valid = false;
}
else
{
valid = check.IsMatch(ipaddr, 0);
}
return valid;
}
private void txtIPAddress_Validating(object sender, CancelEventArgs e)
{
string address = txtIPAddress.Text;
if (!IsValidIP(address))
{
MessageBox.Show("Invalid IP address!");
e.Cancel = true;
}
}
private void cmbMaskBits_Validating(object sender, CancelEventArgs e)
{
int MaskBitsValue = Convert.ToInt32(cmbMaskBits.Text);
if (MaskBitsValue<1 || MaskBitsValue>30)
{
MessageBox.Show("Please select a 'Mask Bits' value between 1 and 30!");
e.Cancel = true;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
// Stop the validation of any controls so the form can close.
// Note: The CausesValidation property of this <Cancel> button
// must also be set to false.
AutoValidate = AutoValidate.Disable;
this.Close();
}
Insert the following as the first line in the validation event of the textbox:
//Allow the form to be closed
if (this.ActiveControl.Equals(sender))
return;
Since the close event of the form is triggering validation and since that would (typically at least) be the only form event that would trigger validation we can make the assumption that any form event triggering validation is the close event.
The actual answer is ridiculously simple compared to all the suggestions here which involve hacks and extra superfluous code to undo something.
The "trick" is just to allow the focus to change and not fire validation from buttons on the form itself.
You can simply set two properties on the form:
MyForm.CausesValidation = false;
MyForm.AutoValidate = AutoValidate.EnableAllowFocusChange;
Et voila, form acts normal when you try to close it and validation still works following other inputs such as tab changing focus or mouse clicks.
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
// Assume that X has been clicked and act accordingly.
}
Create a closing event, then simply cancel your validator.
Try to set CauseValidation to false
or see here : How to skip Validating after clicking on a Form's Cancel button
Or try set this in formClosing event
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// CauseValidation to false or check
}
What you need is an implementation like the one described below, where it is assumed that you have a Save button and a Cancel button for the form:
public Form1()
{
// Disable validation in constructor
textBox.CausesValidation = false;
}
private void OnSaveClicked(object sender, EventArgs e)
{
textBox.CausesValidation = true;
if (ValidateChildren())
{
//
// Do saving of the form data or other processing here ....
//
Close();
}
//
// Set validation to false, as user may press Cancel next
//
textBox.CausesValidation = false;
}
private void OnCancelClicked(object sender, EventArgs e)
{
Close();
}
Check which button has focus in the validation check. If cancel button (and in my case a clear button), override. This is an inner method I call from my cell validating event handler. (Just realized it was a C# question, but you can translate)
Private Sub validateCell(ByVal tagDesc As String, ByVal userInput As String, ByVal legalRegex As String, ByVal regexDesc As String, ByVal e As DataGridViewCellValidatingEventArgs)
Dim match As Match = Regex.Match(userInput, legalRegex)
Dim matches = match.Groups()
Dim val = match.Value
If val.Length = 0 Or userInput.Length > val.Length Then
tagGrid.Rows(e.RowIndex).ErrorText = _
tagDesc & " must match pattern: " & regexDesc
If Me.Cancel_Button.Focused Or Me.clearButton.Focused Then
e.Cancel = False
tagGrid.Rows(e.RowIndex).ErrorText = ""
Else
e.Cancel = True
MsgBox(tagDesc & " must match pattern: " & regexDesc, MsgBoxStyle.Critical)
End If
Else
e.Cancel = False
tagGrid.Rows(e.RowIndex).ErrorText = ""
End If
End Sub
I came here in search of a simple method to cause a form to close when a Validating event handler raises an exception, reports it, and needs to force the form to close. After reading this topic and numerous others, followed by an afternoon of experimenting, I have made several discoveries, and developed a simple hack to force the form to close.
First things first, though; I discovered that when a Validating event calls this.Close() the FormClosingEventArgs.Cancel flag passed into its From_Closing event procedure is set to TRUE, effectively causing the event to cancel itself. Conversely, a normal Close event receives a FormClosingEventArgs.Cancel flag set to FALSE.
Since the Close method on a form takes no arguments, there is no direct way to force the issue, giving rise to the need for a hack. This article discusses a number of such hacks, but I think mine is much simpler to implement.
The hack starts with a simple form level Boolean variable.
bool _fExceptionIsFatal = false;
Other than defining a Form_Closing event handler, this is the only structural change required to the form.
The Form_Closing event is straightforward.
private void From1_Closing ( object sender , FormClosingEventArgs e )
{
if (this.CausesValidation )
{ // There is no sense repeating this procedure if another routine already did it.
DisableValidation ( );
} // if (this.CausesValidation )
if ( _fExceptionIsFatal )
{ // Cancel False == Allow form to close.
e.Cancel = false;
} // if ( _fExceptionIsFatal )
} // From1_Closing
Though DisableValidation is implemented as a local method of the current form, the same thing could be accomplished by passing a Form reference into a library routine, since a Form is a Form, and its Controls collection is a Controls collection, period. Before long, I'll do so, along with implementing its inverse, to turn validation on again.
private void DisableValidation ( )
{
foreach ( Control ctrl in this.Controls )
{
ctrl.CausesValidation = false;
} // foreach ( Control ctrl in this.Controls )
this.CausesValidation = false;
} // DisableValidation
The fourth piece of the solution is equally straightforward; whenever you want to force the form to close, set _intValueAsInteger to TRUE before you call this.Close.
Add below code to your form. You can close the form even the children controls are validating.
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x10) // The upper right "X" was clicked
{
this.ActiveControl = null;
this.AutoValidate = AutoValidate.Disable;
}
base.WndProc(ref m);
}
This question is pretty old but thought of adding the answer anyway:
In the form constructor:
this.FormClosing += Form1_FormClosing;
In the closing event handler (Make sure CausesValidation for the form is set to true to begin with. You could also check the textbox's CausesValidation property instead of the form's) :
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (this.CausesValidation)
{
DisableValidation();
this.Close();
}
}
In the DisableValidation method, disable validation for the textboxes and the form (I am using 2):
private void DisableValidation()
{
txtbox1.CausesValidation = false;
txtbox2.CausesValidation = false;
CausesValidation = false;
}
I have a webusercontrol with a few controls on it like some labels,a textbox and eventually a button. The purpose of this control is to add it to my main page in a placeholder every time I click on the button on the webusercontrol.
This is the code behind my button on my webcontrol
protected void btnCriteriaToevoegen_Click(object sender, EventArgs e)
{
//New eventhandler == all of the eventhandlers of all the objects who have subscribed to the event.
EventHandler eventhandler = ButtonDoorgaan;
ButtonOpslaanEvent mijnevent = new ButtonOpslaanEvent();
//Basic variables I will give with my costum event(ButtonOpslaanEvent)
mijnevent.Naam = txtCriteriumNaam.Text;
mijnevent.Score = Convert.ToInt16(DdlCriteriumScoreSchaal.SelectedValue);
int weging = Convert.ToInt16(DdlCriteriumWeging.SelectedValue) - 1;
mijnevent.Weging = Convert.ToInt16(weging);
//If the eventhandler is not null, for every object that has an eventhandler, execute it.
if(eventhandler!=null)
eventhandler(sender, mijnevent);
}
The eventhandler that need to be executed when the event is fired is defined in my main page like this :
private void critlijn_ButtonDoorgaan(object sender, EventArgs e)
{
ButtonOpslaanEvent eigenevent = (ButtonOpslaanEvent)e;
IEnumerator<Domein> domeinenumerator = domeinen.GetEnumerator();
while (domeinenumerator.MoveNext())
{
if (domeinenumerator.Current.DomeinNaam.Equals(lijstdomeinitemgeselecteerd))
{
Criterium nieuwcriterium = new Criterium();
nieuwcriterium.CriteriumNaam = eigenevent.Naam;
nieuwcriterium.CriteriumScore = Convert.ToString(eigenevent.Score);
nieuwcriterium.CriteriumWeging = Convert.ToString(eigenevent.Weging);
domeinenumerator.Current.Criteriums.Add(nieuwcriterium);
}
}
btnCriteriaToevoegen_Click(sender, e);
}
The btnCriteriaToevoegen_Click event fires and then calls this method(addCriteriaButton()), which will add the button onto the placeholder in my main page:
private void addCriteriaButton()
{
Criterialijn criterialijn = (Criterialijn)LoadControl("~/Criterialijn.ascx");
//Add eventhandlers to control
criterialijn.ButtonDoorgaan += new EventHandler(critlijn_ButtonDoorgaan);
criterialijn.Aangevinkt += new EventHandler(critlijn_Aangevinkt);
//Every control on the page except this one, not enabled
IEnumerator<Criterialijn> criterialijnenumerator = criteriacontrols.GetEnumerator();
while (criterialijnenumerator.MoveNext())
{
criterialijnenumerator.Current.Enabled = false;
}
//Add it to a list of webusercontrols that are currently on screen
criteriacontrols.Add(criterialijn);
criterialijn.Enabled = true;
//Add to placeholder
plhCriteria.Controls.Add(criterialijn);
}
So when all this is said and done, and I run my program, he adds the control to my placeholder, but when I click on the button, he does not add a new control to my placeholder, and just clears my placeholder for some reason. Normally everything should be fine, but I have tried to see if he actually fires the event when you click on the button, and he does not. I have tried to give you a sample of my code, because the code of the whole page is quite big and that would not help you at all. Any ideas why he is not firing the event of the button?
So when your button that you dynamically added posts back, a new page instance is created and that button no longer exists (since you only added it on the previous button click), it has not been recreated.
You must re-create dynamic controls on each postback
Remeber, a new instance of the Page class is created for each postback, any previously created controls, event handlers will not exists in the new instance unless you explicitly re-create them.
I assume these Criteria are some sort of tree structure the user can navigate through (and hopefully arriving at the end somewhere ?).
About btnCriteriaToevoegen_Click:
Why are you defining an event inside a method?
In critlijn_ButtonDoorgaan and addCriteriaButton:
Instead of using an enumerator, just use
foreach(var control in criteriacontrols)
control.Enabled = false;
So yeah, fair to say it's still not quite comprehensable, but it least I tried right? :)
EDIT
ok, then I have this question:
The eventhandler that need to be
executed when the event is fired is
defined in my main page like this :
How sure are you that, when you do
EventHandler eventhandler = ButtonDoorgaan;
the variable "eventhandler" gets all eventhandlers attached to ButtonDoorgaan ?
EDIT 2 (the return)
See Richard Friend's answer; your control is not there anymore