tags:

views:

81

answers:

6

EDIT: for those who come here with a similar problem, now i know this was a BAD IDEA.

hi, I have something like this:

bool preventEvents;
protected void Page_Load(object sender, eventargs e)
{
    preventEvents = doSomeValidation();
}

protected void Button1_Click(object sender, EventArgs e)
{
    if (preventEvents) return;  
    // ...
}

protected void Repeater1_DataBound(object sender, EventArgs e)
{
    if (preventEvents) return;  
    // ...
}

The problem is that I have A LOT of events on the page.

Is it possible to just cancel all further events without adding the "if" line on every method?


EDIT:

got some interesting answers (thanks to everyone) but not what i was looking for, maybe i should be more specific:

given some condition, is it possible to skip all events after Page_Load and just jump to the rendering, without manually removing/mapping each event?

A: 

Use a custom validator, and then it just falls into your standard invalid check.

Mark Brackett
thx, but that way i'd have to put if (Page.IsValid) right?... so is pretty much the same problem =/
y34h
@y34h - Why aren't you checking IsValid anyway? Do you not have any validators, and never plan to have any? A simple regex should do the trick - but if you have so many events on your page that you haven't added the code in the last 6 hours...well, I feel for you. ;)
Mark Brackett
code is in my office and i'm at home ^^ ... anyway, that project ended few days ago, i was just looking for better ways to do that next time
y34h
A: 

You can use the following but it will be almost the same cost

Protected void Page_Load() {
   if (preventEvents) {
      textbox1.TextChanged -= textbox1_TextChanged;
      dropdownlist1.SelectedIndexChanged -= dropdownlist1_SelectedIndexChanged;
      // and so on
   }
}
sh_kamalh
A: 

You can create wrapping delegate over event handler, something like this:

    private EventHandler CreateCancelableEventHandler(EventHandler handler)
    {
        return (sender, e) =>
                   {
                        if (!preventEvents)
                        {
                            handler.Invoke(sender, e);
                        }
                   };
    }

The disadvantage of this solution is that you will need to subscribe to all events in code-behind, not in the markup. Usage of the subscribing would be like this:

button1.OnClick += CreateCancelableEventHandler(Button1_OnClick);
Andrew Bezzub
A: 

How about setting AutoEventWireup to False in your page directive? ie.

<%@ Page Language="C#" AutoEventWireup="false" Inherits="MyWebApp.EventWireUpFalse" %>

That way only events you explicitly "wire-up" in OnInit will be called. This will give you far more control of what events are raised in the page life-cycle.

Dan Diplo
A: 

You can't "jump ahead" to the rendering because there aren't any conditionals in ProcessRequestMain to allow for it. The only option is to hack the event handlers of the relevant controls.

protected void Page_Load(object sender, EventArgs e) {
    // DON'T DO THIS!! Years from now, some poor soul tasked with
    // debugging your code will tear their hair out, until they
    // discover the unholy magic you have conjured herein. Keep in mind
    // this is the 21st century and this person knows where you live.
    // 
    // Seriously, just use the validation built in to ASP.NET.
    if ("true".Equals(Request.QueryString["disable_events"], StringComparison.OrdinalIgnoreCase)) {
        // disable *all* event handlers on button controls
        foreach (var b in this.GetControlDescendants().OfType<Button>()) {
            var eventList = (EventHandlerList) typeof (Control)
                .GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic)
                .GetValue(b, null);
            typeof (EventHandlerList)
                .GetField("head", BindingFlags.Instance | BindingFlags.NonPublic)
                .SetValue(eventList, null);
        }
    }
}

Utility extension method for completeness:

/// <summary>
/// Performs a breadth-first traversal of a control's control tree. Unlike
/// FindControl, this method does not descend into controls that have not
/// called EnsureChildControls yet.
/// </summary>
/// <returns>Enumerable of the visited controls.</returns>
public static IEnumerable<Control> GetControlDescendants(this Control parent) {
    // Don't force execution of EnsureChildControls
    if (!parent.HasControls()) yield break;

    foreach (Control child in parent.Controls) {
        yield return child;
    }
    foreach (Control child in parent.Controls) {
        foreach (var descendant in child.GetControlDescendants()) {
            yield return descendant;
        }
    }
}
Michael Kropat
nice one, i'll give it a try(just for academical purposes, i now understand what demons i was about to unleash)
y34h
+1  A: 

The problem is that I have A LOT of events on the page.

Yes, that is a problem. Many events in the same page are bad for performance (it means you're storing a lot of state and doing many http requests). They are bad for maintainability (you have a lot of code in the same class that's all jumbled together). They are bad for testability (asp.net events are notoriously hard to unit test). And they are bad for usability (can't bookmark, don't work with the back button, can lead to double posts).

The solution is to use the Post/Redirect/Get pattern. The downside is that it will mean re-thinking parts of your application design, but in the end you'll have an app that just works better and faster and is easier to maintain.

Be careful choosing to just skip event processing, as is your plan. Odds are your current page state is the result of several events, and not processing events can break the expected state of your page.

Joel Coehoorn
well that's true, and i'm in fact ashamed of what i've coded there, but it's to late to refactor it
y34h
+1`redesign over jury rigging any day of the week.
Mike Burton