I am creating a gridview dynamically using Itemplate but I have run into an issue where the event handlers I create for my drop down boxes in edititem template are accumulating every time it fires.

To be more specific. When I enter edit mode and select a new item in the dropdownlist the event handler fires twice (this I know is because the event handler is updating a second dropdownlist), but if I change another dropdownlist during the same edit session or change the same dropdownlist again the new event fires then the original two fire again. Then if I make a third change I get four events and it keeps incrementing.

I am removing the orignal event handler before adding a new event handler so there shouldn;t be multiple handlers for each instance.

else if (ControlType == "DropDown")
                    {
                        var dropVals = new Dictionary<string, string>();
                        DropDownList field_dropbox = new DropDownList();
                        
                        field_dropbox.ID = FieldName;
                        field_dropbox.SelectedIndexChanged -= new EventHandler(field_dropbox_SelectedIndexChanged);
                        field_dropbox.SelectedIndexChanged += new EventHandler(field_dropbox_SelectedIndexChanged);
                        field_dropbox.AutoPostBack = true;

My event handler updates another dropdown so I know why the event should fire twice but it doesn't explain why they keep firing.

protected void field_dropbox_SelectedIndexChanged(Object sender, EventArgs e)
        {
            string syncDrop = "";
            string list = "";
            var _sync = new Dictionary<string,string>();
            
            _sync = GlobalVars._DropSync;
            list = ((DropDownList)sender).ID.ToString();

            if (_sync.ContainsKey(list))
            {
                syncDrop = _sync[list].ToString();
                
                GridViewRow gvr = (GridViewRow)(((Control)sender).NamingContainer);

                // Get the reference of the first DropDownlist that will generate this SelectedIndexChanged event
                DropDownList dropdownlist1 = (DropDownList)gvr.FindControl(list);

                // Get the reference of second DropDownlist in the same row.
                DropDownList ddlSync = (DropDownList)gvr.FindControl(syncDrop);

                if (ddlSync != null)
                {
                    ddlSync.ClearSelection();
                    //ddlParagraph.Items.FindByText(dropdownlist1.SelectedItem.Value.ToString()).Selected = true;
                    ddlSync.Items.FindByText(dropdownlist1.SelectedValue.ToString()).Selected = true;
                }                
                
            }
            //new Page().Session["EventhandlerFired"] = ((DropDownList)sender).ID;
                      
           

        }

Is there a way to purge the eventhandler after it is fired so it does not fire if I make a subsequent change?

I am removing the orignal event handler before adding a new event handler so there shouldn;t be multiple handlers for each instance.

else if (ControlType == "DropDown")
                    {
                        ...
                        field_dropbox.SelectedIndexChanged -= new EventHandler(field_dropbox_SelectedIndexChanged);
                        field_dropbox.SelectedIndexChanged += new EventHandler(field_dropbox_SelectedIndexChanged);
                        ...

In the above, I don't understand why you are removing the event handler and then adding the same event handler right back...


If you want to stop the handler from processing when you are programmatically changing the item that causes the event to fire again, you can set a variable that indicates you are doing just that:

bool bInSelectedChangedEvent = false;

protected void field_dropbox_SelectedIndexChanged(Object sender, EventArgs e)
        {
            if (!bInSelectedChangedEvent)
            {
                // set flag to true to prevent processing while we are changing the item that causes the event to fire again...
                bInSelectedChangedEvent = true;

                // all the processing code in here...
            }
            bInSelectedChangedEvent = false;
         }

However, you might have a design problem if you are modifying another control that is tied to the same event handler, which could then modify another control that is tied to the same event handler, which could then modify another control that is tied to the same event handler, which could then....etc. etc. etc.

Is there a way to purge the eventhandler after it is fired so it does not fire if I make a subsequent change?

Not sure what you mean by purge, but if you can't use the recommendation above and you want to remove all event handlers associated with the control's event, just assign it null:

comboBox1.SelectedIndexChanged = null;

The above null assignment will remove all event handlers from that event member.

DdoubleD -- Are you sure about removing the event handler?

private void button1_Click(object sender, EventArgs e)
    {
      comboBox1.SelectedIndexChanged = null;
    }

That code won't compile for me. In my Delphi days that is exactly how you cleared event handlers and I like that design but I have never figured out a way you could do it in .NET. As far as I know you have to reflect in to the event handler so you can -= all event handler references. Could you please elaborate on it? I would really like to know if something like that could be done

[edit]
cgyrob -- Can you upload a sample application demonstrating the problem?
[/edit]

Edited 7 Years Ago by sknake: n/a

DdoubleD -- Are you sure about removing the event handler?

private void button1_Click(object sender, EventArgs e)
    {
      comboBox1.SelectedIndexChanged = null;
    }

That code won't compile for me. In my Delphi days that is exactly how you cleared event handlers and I like that design but I have never figured out a way you could do it in .NET.

You are right, that won't work! I had somewhere you could this, but had never tried to do it--obviously. I agree it would be nice. Good catch sknake!

Dang :(

I was hoping there was something I hadn't tried with clearing event handlers. They are one of the biggest culprits in object references being maintained and stopping garbage collection, ie memory leaks.

@DdoubleD

Thanks for the reply. i added the removal on the eventhandler on Friday because i found a blog with someone who had a similar problem and adding the removal of the eventhandler helped him. It had no affect on my code at all which is why I finally decided to ask around.

As for the purging I just want to remove any reference to the event once it is processed so it does not run again if I make subsequent changes to any drop downs within the same sequence. I should be able to change a dropdown over and over with only firing the current event only.

@Sknake
I will look at modifying my code on Monday to run without my AD and DB connections.

Thanks for the replies.

I tried one more thing before sending out this copy. I tried to create different event handlers if the field was an ID field or a DESC field but the page still has the same functionality which is really making me scratch my head.

Now Instead of firing the same event handler twice with the ID field firing first it is firing the ID event handler first even if I change the DESC dropdown. I can change the ID field anytime but can only change the DESC if I try it first.

I was able to pull this page out of my project and modify it enough to work using some lists and one table. I provided a script to create and load one table. I also changed the program to use Sqlserver as I know there are more people with access to sql server then oracle.

If anyone has any ideas it would be appreciated because I am totally confused why it is functioning like this.

The only thing I could think of is that your old values may be stored in the viewstate and when you fire it is not accumulating events for every change you make but rather for each dropdown you change.

Example:
DrownA Original Value: "A"
DrownB Original Value: "A"
DrownC Original Value: "A"

New Values:
DrownA Original Value: "Z"
DrownB Original Value: "Z"
DrownC Original Value: "Z"

The event will fire three times:
DrownA Original Value: A -> Z
DrownB Original Value: A -> Z
DrownC Original Value: A -> Z

This code also raises an exception sometimes:

if (ddlSync != null)
                {
                    ddlSync.ClearSelection();
                    ddlSync.Items.FindByText(dropdownlist1.SelectedValue.ToString()).Selected = true;
                }

As for how to fix this I don't know -- I don't understand what the problem is exactly. I am able to modify fields and it retains the changes, and the item count in the dropdown isn't accumulating. Can you step me through reproducing this behavior?

The exception is caused because the test data in the table does not match all the dropdownlist, I don't have any issues with the full dataset.

To re-create

The problem is only with the drop down lists I am trying to keep in sync, all the other lists work fine.

When you open the app in edit mode, first change the value in the drop down list cpm_line_name, this will work correctly the first time. Now try changing this value again, it will not work for any subsequent updates as the event handler for cpm_line_id fires first changing the value back to the original before firing its own event. I can change the line_id value updating the name field correctly as many times as I want. The problem only occurs on the name field that I am trying to keep in sync.

If you step through you will see that the event handler for the line id fires first every time.

I was perplexed as to why the line_id event fired first every time so I changed my select to pull the line_name first in the row and then the line_name event fired first every time and I could not update the line_id only the line_name.

For some reason the firing of the events seem to be linked to the order of the fields in the row created in the template and not the sequence in which thy were triggered.

Never heard any mention of this while trying to figure out this problem.

@sknake - a little update.

After looking further into my problem I believe this has to do with Itemplate is controlling the events for all the controls that are held in it; this is why the events fire in the same order everytime.

I read that I need to bubble up the event to the page so they will be handled by the page and not by the template control. I have never used this technique but I will give it try and let you know how it worked.

Just an update. I bubbled up the events to the page but still was having the same issue.

Because of time constraints I have let go of trying to sync these tables bilaterally and will have them insert the id and update the desc on index change. It is an internal app and they know the id's so it isn't a major issue.

Maybe if I find the time I will figure the bilateral sync at a later date, shouldn't be as difficult as I was making it.

Thanks for all the help.

This question has already been answered. Start a new discussion instead.