TwinHabit
TwinHabit

Reputation: 753

EventHandlers of dynamic controls created in a ListView are not fired, if the ListView is bound in Page_Load

In our intranet ASP .NET application we use an architecture approach which is similar to the MVVM pattern. Our viewmodel, which describes the state of the view, is either created or loaded in Page_Load from the ViewState. Depending on the viewmodel content the page then is dynamically created. Right now I am facing a problem where I cannot find an elegant solution.

The problem is that we have to handle events that are fired by the controls, which are dynamically created in the ListView. However, those registered events do only fire, if the listView is databound in Page_Init. If the databinding takes place in Page_Load those events are not fired. The thing now is, that we need our ViewModel in order to databind the ListView to it. This ViewModel is cached in the ViewState, which - to my knowledge - only comes accessible in Page_Load. That means that in Page_Init we cannot access the ViewModel.

I created the following example:

ASP:

<form id="form1" runat="server">
    <asp:ListView runat="server" ID="lstView" ItemPlaceholderID="itemPlaceHolder">
        <LayoutTemplate>
            <asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
        </LayoutTemplate>
        <ItemTemplate>
            <asp:DropDownList runat="server" ID="dropDown" SelectedValue='<%# Bind("SelectedValue") %>' DataSource='<%# Eval("Choice") %>' AutoPostBack="true" />
        </ItemTemplate>
    </asp:ListView>
</form>

Code Behind:


namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Init(object sender, EventArgs e)
        {
                     //if i put the Initialization logic here, the event gets fired, however the Model is not accessible from the viewstate

        }

        protected void Page_Load(object sender, EventArgs e)
        {
            InitializeModel();

            lstView.DataSource = _model.NestedModels;
            lstView.ItemCreated += (k, args) =>
            {
                var dropDown = (DropDownList)args.Item.FindControl("dropDown");
                dropDown.SelectedIndexChanged += new EventHandler(dropDown_SelectedIndexChanged);
            };
            lstView.DataBind();
        }

        void dropDown_SelectedIndexChanged(object sender, EventArgs e)
        {
            Response.Write("Selected Index Changed fired");
        }

        private MyModel _model;
        void InitializeModel()
        {
            if (ViewState["model"] == null)

                ViewState["model"] = new MyModel();

            _model = (MyModel) ViewState["model"];

        }
    }

    [Serializable]
    public class MyModel
    {
        [Serializable]
        public class NestedModel
        {
            public NestedModel()
            {
                Choice = new List(new[] { "Value1", "Value2", "Value3", "Value4", "Value5" });
            }

            public string SelectedValue { get; set; }

            public List Choice { get; set; }
        }

        private List _nestedModels = new List();

        public MyModel()
        {
            Init();
        }

        public List NestedModels
        {
            get { return _nestedModels; }
        }

        void Init()
        {
            NestedModels.Add(new NestedModel() {SelectedValue = "Value1"});
            NestedModels.Add(new NestedModel() { SelectedValue = "Value2" });
            NestedModels.Add(new NestedModel() { SelectedValue = "Value3" });
            NestedModels.Add(new NestedModel() { SelectedValue = "Value4" });
            NestedModels.Add(new NestedModel() { SelectedValue = "Value5" });
        }
    }
}

I hope one of you guys knows a way either to preserve my event to get fired or to retrieve my cached ViewModel in Page_Init.

Best Regards, TH

Upvotes: 1

Views: 1052

Answers (1)

Muhammad Akhtar
Muhammad Akhtar

Reputation: 52241

You have to override the CreateChildControls event and dynamically add the control there on page postback. This will be called first and then your dynamically event handler is called.

protected override void CreateChildControls()
{
   PopulateControls();//populate your controls here
}

Upvotes: 2

Related Questions