A couple of days ago David Cox pointed out a bug in my West Wind Web Store, where if the user submits the Item form by pressing Enter rather than clicking on the Add button, causes the form to fail.
The code for the Page_Load in this form looks something like this:
private void Page_Load(object sender, System.EventArgs e)
{
if (!this.IsPostBack)
this.DisplayItem();
}
private void btnSubmit_Click(object sender, System.EventArgs e)
{
...
}
with a btnSubmit handler routine below that is hooked up to the actual Submit button event. The handler among other things performs the task of re-displaying the item in case of failure or submitting the item to the shopping cart.
The code above works on the logic that any databinding and display of the item data only needs to happen during GET operations (ie, first access to the page) and any other operations on this page cause a submission of the form – IOW, the btnSubmit_Click() event would fire.
The code above works fine in most cases. If the user clicks the button – no problem. In most cases when the user just presses enter it also works as text fields on a form are implicitly self-submitting in HTML.
However, Internet Explorer is somewhat flakey in how it submits forms in this way. In this example, doing a trace reveals that the btnSubmit does not get POSTed when doing a submit from the TextBox. The same operation works fine in Firefox, which (correctly I think) submits the form with the single button in it.
There are several other forms in this application where Internet Explorer DOES submit the button. For example, on the OrderProfile.aspx page, users can press ENTER at any point and the form will sumit properly.
I've tried to understand what makes IE behave differently but I can't see any difference. Neither page has any special form submission or button code but one works the other doesn’t. Go figure.
The solution to the problem for the Item page of course is simple, IF YOU KNOW AND TEST FOR THIS SITUATION. And that’s a big if if the browser you’re testing with is sometimes working one way and sometimes another. The quick fix is:
private void Page_Load(object sender, System.EventArgs e)
{
if (!this.IsPostBack)
{
this.DisplayItem();
}
else
{
// *** Must handle case where user is 'auto-submitting'
// without clicking the button.
if ( Request.Form["btnSubmit"] == null )
this.btnSubmit_Click(this,EventArgs.Empty);
}
}
which basically forces the form submission to occur if for whatever reason the form submission button hasn’t been provided.
It might actually make sense to create a DefaultButton property on the form and point it at a handler, and then hook this up in the OnLoad() event of a custom form base class:
// *** In base Page class
protected override void OnLoad(EventArgs e)
{
base.OnLoad (e);
if ( this.IsPostBack &&
this.DefaultButton != null &&
Request.Form[this.DefaultButton.ID] == null )
{
MethodInfo Meth = this.DefaultButton.GetType().GetMethod("OnClick",
BindingFlags.Instance | BindingFlags.NonPublic);
Meth.Invoke(this.DefaultButton,new object[1] { EventArgs.Empty });
}
}
Note that you have to use Reflection to make this happen since the OnClick() handler that fires the event is protected on the Button object. It actually took me a bit to figure out how to do this. I keep forgetting that you can’t access the Event directly by either calling the method or even as a Delegate like this:
DefaultButton.Click.Invoke(…)
In fact, I don’t know of a way to directly access the event in any way other than assignment (+=) or removal (-=) from client code. Hence the requirement for Reflection. The above also isn’t truly generic – it works on internal knowledge (and convention in the .NET framework) that there’s an OnClick() method that is responsible for firing the event. If there wasn’t such a ‘firing method’ handy, a lot more work would be needed to get the EventInfo object, retrieve the RaiseMethod() and then fire it on the Page object. Yuk…
It sure would be a lot nicer if we could somehow get a reference to the Delegate:
EventHander e = DefaultButton.Click as EventHandler;
e.Invoke(…);
But no such luck. Maybe somebody knows of an easier way to do this.
Anyway, the code above works reliably only if you have a single submit button. If you have more than one button submission on a form you’d need a slightly more elaborate scheme that checks all possible button submissions to make sure you don’t submit if another button was submitted. If you use a common naming scheme (like btn prefix) this is easy and you can modify the code above to check for any button that starts with the prefix in the Form[] collection.
Other Posts you might also like