Force a control to DataBind from callback function executed in modal

579 views Asked by At

I am working on a Kentico Webforms project, my requirement is to provide a modal window that allows us to update a value within a parent control.

The parent control sets a static callback function that is executed from the modal when a selection is made. The call back executes within the modal form passing back and setting the correct value. I call DataBind() on the updated control but the value is not updated and if I set up a DataBinding callback it is not executed

//Static container for call back reference
public static class CallbackContainer
{
    public static Action<string> Callback { get; set; }
}

Parent control

protected override void OnPreRender(EventArgs e)
{
    //Set callback
    CallbackContainer.Callback = id => Value = id;

    txtOrgName.DataBinding += (sender, args) =>
    {
        //Never executes
        Debugger.Break();
    };
}

public override object Value
{
    get
    {
        return txtOrgName.Text;
    }
    set
    {
        txtOrgName.Text = value.ToString();
        txtOrgName.DataBind();

        Page.DataBind();
        DataBind();
    }
}

Modal form

//Executed on selection
protected void userGrid_OnAction(string actionName, object actionArgument)
{
    //Callback passing selected value
    CallbackContainer.Callback(actionArgument.ToString());
}

Any ideas??

1

There are 1 answers

0
martinh_kentico On

If I understand your code correctly, the callback seems to have closure on the control instance from the previous request at the time it is called.

userGrid_OnAction is called within the post actions phase of the page life-cycle, which is just after the Load and before PreRender so the execution takes place in this order:

Parent1.Load
Child1.Load
Parent1.PreRender
- CallbackContainer.Callback = set Parent1.Value
Child1.PreRender

Parent2.Load
Child2.Load
Child2.userGrid_OnAction
- set Parent1.Value
Parent2.PreRender
- CallbackContainer.Callback = set Parent2.Value
Child2.PreRender

While Parent1 and Parent2 are objects from different requests

You can start with moving the callback assignment from PreRender to OnLoad, but the code still won't be thread safe as you will be sharing one static state for all the requests to the same page and they may collide.

This is how the life cycle will look like after that change:

Parent2.Load
- CallbackContainer.Callback = set Parent2.Value
Child2.Load
Child2.userGrid_OnAction
- set Parent2.Value
Parent2.PreRender
Child2.PreRender

But the requests may happen also this way:

Parent2.Load
- CallbackContainer.Callback = set Parent2.Value
Parent1.Load
- CallbackContainer.Callback = set Parent1.Value
Child1.Load
Child2.Load
Child2.userGrid_OnAction
- set Parent1.Value
Parent2.PreRender
Child2.PreRender
Parent1.PreRender
Child1.PreRender

To make that property request-specific so that individual requests don't collide you can use code similar to this:

public static class CallbackContainer
{
    public static Action<string> Callback 
    { 
       get
       {
         return (Action<string>)HttpContext.Current.Items["CallbackContainer.Callback"];
       }
       set
       {
         HttpContext.Current.Items["CallbackContainer.Callback"] = value;
       }
    }
}