WebForms嵌套用户控件数据绑定

时间:2017-12-29 17:07:30

标签: c# asp.net events data-binding webforms

我使用嵌套的用户控件实现了一些东西并且遇到了与数据绑定相关的问题,所以我创建了一个小应用程序来尝试调试行为。

我有一个包含单个用户控件的默认页面(aspx),' ChildControl'。在后面的代码中,我为ChildControl设置了几个属性并在其上调用了DataBind()。

在ChildControl用户控件(ascx)中,我有一个' GrandchildControl'的ListView。 ListViewItems,其数据源绑定到在Default.aspx的LoadPage()方法中设置的属性。我还绑定了GrandchildControl的一个属性,该属性将用于该用户控件中的DropDownList。在这个用户控件的代码中,我有一个click事件处理程序,它只是将一个新的User对象添加到一个会话变量中,并调用Default.aspx的LoadPage()方法。

在GrandchildControl用户控件(ascx)中,我显示每个绑定用户对象的信息。

我添加了日志以查看调用事件的顺序。当我导航到页面(而不是回发)时,事件按预期按以下顺序触发:

DEFAULT PAGE LOAD
GRANDCHILD CONTROL ITEM DATA BOUND
GRANDCHILD CONTROL ITEM DATA BOUND
CHILD CONTROL PAGE LOAD
GRANDCHILD CONTROL PAGE LOAD
GRANDCHILD CONTROL PAGE LOAD

但是,当我单击ChildControl中的LinkBut​​ton添加新的User对象时,事件按此顺序触发:

DEFAULT PAGE LOAD
CHILD CONTROL PAGE LOAD
GRANDCHILD CONTROL PAGE LOAD
GRANDCHILD CONTROL PAGE LOAD
ADD INCOME CLICKED
GRANDCHILD CONTROL PAGE LOAD
GRANDCHILD CONTROL ITEM DATA BOUND
GRANDCHILD CONTROL PAGE LOAD
GRANDCHILD CONTROL ITEM DATA BOUND
GRANDCHILD CONTROL PAGE LOAD
GRANDCHILD CONTROL ITEM DATA BOUND

如您所见,在调用各自的页面加载触发后,User对象被绑定到ListView。因此,下拉选项未正确设置(它们都默认为0索引)。

所以我的问题是,是什么原因导致ucChildControl.DataBind()在最初加载页面时表现不同,而不是从ChildControl的点击处理程序的上下文中调用它?

我为这篇长篇文章道歉,但希望尽可能详细地展示我搜索过的内容,并且无法找到类似的问题和解决方案。

所有代码如下:

型号:

public class DropdownContainer
{
    public List<DropdownValue> DropdownValues { get; set; }
}

public class DropdownValue
{
    public string DisplayText { get; set; }
    public string ID { get; set; }
}

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string AgeGroup { get; set; }
}

aspx前端:

<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
    <uc1:ChildControl runat="server" ID="ucChildControl"></uc1:ChildControl>
</asp:Content>

背后的aspx代码:

public partial class Default : Page
{
    private DropdownContainer _ageGroupContainer = new DropdownContainer()
    {
        DropdownValues = new List<DropdownValue>()
        {
            new DropdownValue()
            {
                DisplayText = "18-25",
                ID = "1"
            },
            new DropdownValue()
            {
                DisplayText = "26-35",
                ID = "2"
            },
            new DropdownValue()
            {
                DisplayText = "36-45",
                ID = "3"
            }
        }
    };

    private List<User> _userDataSource = new List<User>()
    {
        new User()
        {
            FirstName = "Mickey",
            LastName = "Mouse",
            AgeGroup = "1"
        },
        new User()
        {
            FirstName = "Daffy",
            LastName = "Duck",
            AgeGroup = "3"
        }
    };

    public string Log { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        Log += "DEFAULT PAGE LOAD\n";

        if (!Page.IsPostBack)
        {
            LoadPage();
        }
    }

    public void LoadPage()
    {
        List<User> lstUserTemp = _userDataSource;

        if (Session["usersAdded"] != null)
        {
            lstUserTemp.AddRange((List<User>)Session["usersAdded"]);
        }

        ucChildControl.UserDataSource = lstUserTemp;
        ucChildControl.AgeGroupDataSource = _ageGroupContainer;
        ucChildControl.DataBind();
    }
}

儿童ascx前端:

<div>
    <asp:ListView runat="server" ID="lvChild" DataSource='<%# UserDataSource %>' OnItemDataBound="lvChild_ItemDataBound">
        <ItemTemplate>
            <uc2:GrandchildControl runat="server" ID="ucGrandchildControl" User='<%# Container.DataItem %>' AgeGroupDataSource='<%# AgeGroupDataSource %>'></uc2:GrandchildControl>
            <br />
        </ItemTemplate>
    </asp:ListView>
</div>
<asp:LinkButton runat="server" ID="lbtnAddUser" OnClick="lbtnAddUser_Click" Text="Add User"></asp:LinkButton>

儿童ascx代码背后:

public partial class ChildControl : System.Web.UI.UserControl
{
    public List<User> UserDataSource { get; set; }

    public DropdownContainer AgeGroupDataSource { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        ((Default)Page).Log += "CHILD CONTROL PAGE LOAD\n";
    }

    protected void lvChild_ItemDataBound(object sender, ListViewItemEventArgs e)
    {
        ((Default)Page).Log += "GRANDCHILD CONTROL ITEM DATA BOUND\n";
    }

    protected void lbtnAddUser_Click(object sender, EventArgs e)
    {
        ((Default)Page).Log += "ADD USER CLICKED\n";

        List<User> usersAdded = (List<User>)Session["usersAdded"];

        if (usersAdded == null)
        {
            usersAdded = new List<User>();
        }

        usersAdded.Add(new User());

        Session["usersAdded"] = usersAdded;

        ((Default)Page).LoadPage();
    }
}

孙子ascx前端:

<div>
    <asp:Label runat="server" Text="User Name: "></asp:Label>
    <asp:TextBox runat="server" ID="txtUserName" Text='<%# string.Format(@"{0} {1}", User.FirstName, User.LastName) %>'></asp:TextBox>
</div>
<div>
    <asp:Label runat="server" Text="Age Group: "></asp:Label>
    <asp:DropDownList runat="server" ID="ddlAgeGroup" DataSource='<%# AgeGroupDataSource.DropdownValues.OrderBy(x => Convert.ToInt32(x.ID)) %>' DataTextField="DisplayText" DataValueField="ID" OnSelectedIndexChanged="ddlAgeGroup_SelectedIndexChanged" AutoPostBack="true"></asp:DropDownList>
</div>

孙子ascx代码背后:

public partial class GrandchildControl : System.Web.UI.UserControl
{
    public User User { get; set; }

    public DropdownContainer AgeGroupDataSource { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        ((Default)Page).Log += "GRANDCHILD CONTROL PAGE LOAD\n";

        if (User != null)
        {
            ddlAgeGroup.SelectedValue = User.AgeGroup;
        }

        ddlAgeGroup.Items.Insert(0, new ListItem() { Text = "SELECT AN AGE GROUP", Value = string.Empty });
    }

    protected void ddlAgeGroup_SelectedIndexChanged(object sender, EventArgs e)
    {
        ((Default)Page).Log += "GRANDCHILD CONTROL SELECTED INDEX CHANGED\n";
    }
}

1 个答案:

答案 0 :(得分:0)

如果有人遇到这个问题并且遇到类似的问题,我已经解决了这个问题。

所有下拉选择恢复为0索引的原因是因为在添加其他用户之后进行数据绑定时,每个列表项的页面加载事件都在数据绑定事件之前调用(如原始问题中所示)。因此,会发生以下情况:

  1. 加载GrandchildControl页面。此时,用户属性为null 它在页面加载后才会设置。发生的唯一事情 这一点是将新列表项添加到下拉列表中。

  2. 页面加载后,所有前端属性都绑定了 调用ItemDataBound事件。绑定下拉数据源时, 先前插入的列表项将被覆盖并且 选择的值不再设置,因此默认为0 索引。

  3. 因此,需要在ItemDataBound事件中插入默认下拉列表选择和所选值的分配。我在下面附上了所有代码更改。

    儿童ascx代码背后:

    protected void lvChild_ItemDataBound(object sender, ListViewItemEventArgs e)
    {
        ((Default)Page).Log += "GRANDCHILD CONTROL ITEM DATA BOUND\n";
    
        //Add call to 'InitializeControls' method of grandchild user control.
        ((GrandchildControl)e.Item.FindControl("ucGrandchildControl")).InitializeControls();
    }
    

    孙子ascx代码背后:

    //Remove initialization logic from page load.
    protected void Page_Load(object sender, EventArgs e)
    {
        ((Default)Page).Log += "GRANDCHILD CONTROL PAGE LOAD\n";
    }
    
    //This method has been added to be called from the ItemDataBound event.
    public void InitializeControls()
    {
        ddlAgeGroup.Items.Insert(0, new ListItem() { Text = "SELECT AN AGE GROUP", Value = string.Empty });
    
        if (User != null)
        {
            ddlAgeGroup.SelectedValue = User.AgeGroup;
        }
    }