Question

First of all, I found a few similar questions. One of them is here , which does not have correct answer.

I'm writing custom server control, which has Text property and Click event. Everything woks fine (Click event is firing and sender object has correct value), but only if I use it only in one place on the page.

This example works fine (if SimpleControl1.Text has value "First control", in response I'm receiving correct value):

protected void SimpleControl1_Click(object sender, EventArgs e)
    {
        SimpleControl sc = sender as SimpleControl;
        if(sc != null)
        {
            Response.Write(sc.Text);
        }
    }

But if I add second control on the same page (SimpleControl2 with text "Second Control"), my first control's Click event will no longer work:

    protected void SimpleControl2_Click(object sender, EventArgs e)
    {
        SimpleControl sc = sender as SimpleControl;
        if (sc != null)
        {
            Response.Write(sc.Text);
        }
    }

So if I click on first control, I'm receiving "Second control" text.

I think I'm missing something, but I'm not sure what.

How to resolve this problem?

Here is my simple Web control:

public class SimpleControl : WebControl, IPostBackEventHandler
{
    public string Text { get; set; }

    protected override void OnInit(EventArgs e)
    {
        Page.RegisterRequiresRaiseEvent(this);
        Page.RegisterRequiresControlState(this);
        base.OnInit(e);
    }

    private static readonly object EventClick = new object();

    protected virtual void OnClick(EventArgs e)
    {
        EventHandler eventHandler = (EventHandler)Events[SimpleControl.EventClick];
        if (eventHandler != null) { eventHandler(this, e); }
    }

    public event EventHandler Click
    {
        add { Events.AddHandler(EventClick, value); }
        remove { Events.RemoveHandler(EventClick, value); }
    }

    protected override object SaveControlState()
    {
        object state = base.SaveControlState();
        return new object[] { state, Text };
    }

    protected override void LoadControlState(object state)
    {
        object[] states = state as object[];
        if (states != null)
        {
            base.LoadControlState(states[0]);
            Text = (string)states[1];
        }
    }

    protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
    {
        writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
        writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
        writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.ClientScript.GetPostBackEventReference(this, "Click"));

        writer.RenderBeginTag("div");
        writer.Write(Text);
        writer.RenderEndTag(); 

        base.RenderContents(writer);
    }

    public void RaisePostBackEvent(string eventArgument)
    {
        this.OnClick(EventArgs.Empty);
    }
}

Edit

markap

<cc1:SimpleControl ID="SimpleControl1" runat="server" 
Text="First control" OnClick="SimpleControl1_Click"  />
<cc1:SimpleControl ID="SimpleControl2" runat="server" 
Text="Second Control" OnClick="SimpleControl2_Click" />

p.s. I also removed Control State support but it didn't fixed the problem.

Was it helpful?

Solution

Remove this line from OnInit:

Page.RegisterRequiresRaiseEvent(this);

The msdn for this method states:

Only one server control can be registered per page request.

http://msdn.microsoft.com/en-us/library/system.web.ui.page.registerrequiresraiseevent.aspx

OTHER TIPS

How are you binding your events? Can you show markup also? I would assume that something odd is happening when you're binding the event, and somehow you've bound the second event to the first control, or something along those lines.

I guess @Crwydryn guess is pretty much spot on if the feature is what you after (or somewhat similar). You can just bind to SimpleControl_Click for both or more controls. Posting your markup will be helpful.

The problem is object state = base.SaveControlState() state may be null. According to MSDN

Returns the server control's current state. If there is no state associated with the control, this method returns null.

public override object SaveControlState()
{
    object obj = base.SaveControlState();
    // Your problem is here
    // return new object[] { obj, Text };
    if (!string.IsNullOrEmpty(Text))
    {
       if (obj != null)
       {
           return new object[] { obj, Text };
       }
       else
       {
           return Text;
       }
    }
    else
    {
        return obj;
    }
}
public override void LoadControlState(object state)
{
    if (state != null)
    {
        object obj = state as object[];
        if (obj != null)
        {
            base.LoadControlState(obj[0]);
            Text = (string)obj[1];
        }
        else
        {
            if (state is string)
            {
                 Text = (string)state;
            }
            else
            {
                 base.LoadControlState(state);
            }
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top