views:

350

answers:

2

I have a Person class that contains properties such a FirstName, LastName, EmployeeID, etc. All of the aforementioned properties are just single strings. The Person class also has some properties that are lists of other objects I have defined. For instance, the Person object has a property called "PhoneNumbers" which is a List<PersonPhoneNumbers>. PersonPhoneNumbers is a class that contains basic properties such as Number, Extension, Type.

Now, I have a web form for editing the Person object. It contains text fields for all of the basic Person properties, and gridviews for displaying the properties that are List<T> types.

I bind all the controls in the code behind. I have no datasource controls in the declarative aspx page.

In the code behind I have a private variable called "_myPerson" that is of type "Person". When the page first loads, it checks the QueryString for an "ID" value and if it exists, it instantiates the "_myPerson" object with that value. This process will go to the database and get the data and populate all the properties of the "_myPerson" object.

I then call a method named "LoadFormControlsFromPerson()" that sets the values for all the form fields. Here is that method:

/// <summary>
/// Fills the form controls from the data in the Person object.
/// </summary>
private void LoadFormControlsFromPerson()
{
    // Fill Data
    txtFirstName.Text = myPerson.FirstName;
    txtMiddleName.Text = myPerson.MiddleName;
    txtLastName.Text = myPerson.LastName;
    txtEmployeeID.Text = myPerson.EmployeeID;

    if (myPerson.SOMRelationshipType.Id != CommonBase.Int_NullValue)
    {
        ddlSOMRelationshipType.SelectedValue = myPerson.SOMRelationshipType.Id.ToString();
    }
    else
    {
        ddlSOMRelationshipType.SelectedIndex = 0;
    }
    cbDisabledFlg.Checked = myPerson.DisabledFlg;

    if (!myPerson.IsNew)
    {
        lblSidePanelID.Text = myPerson.Id.ToString();
        lblSidePanelName.Text = myPerson.FirstName + " " + myPerson.LastName;
    }

    gvPhoneNumbers.DataSource = myPerson.PhoneNumbers;
    gvPhoneNumbers.DataBind();

    SetFormControlsUsability();
}

So far, so good. Everything displays, including my grid of PhoneNumbers (gvPhoneNumbers). The gridview is defined as follows:

<asp:GridView ID="gvPhoneNumbers" runat="server" 
                    AutoGenerateColumns="false" DataKeyNames="ID" >
                    <Columns>
                        <asp:TemplateField>
                            <ItemTemplate>
                                <asp:LinkButton ID="btnEditPhoneNumber" runat="server" Text="Edit" CommandName="Select" />
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:BoundField DataField="Number" HeaderText="Number" />
                        <asp:BoundField DataField="Extension" HeaderText="Extension" />
                        <asp:BoundField DataField="CountryCode" HeaderText="CountryCode" />
                        <asp:TemplateField HeaderText="Type">
                             <ItemTemplate>
                                 <asp:Label ID="lblPersonPhoneNumberRelationshipType" runat="server" Text='<%# Bind("RelationshipType.Name") %>'></asp:Label>
                             </ItemTemplate>
                        </asp:TemplateField>
                        <asp:CheckBoxField DataField="PrimaryFLG" HeaderText="Primary" />
                    </Columns>
                    </asp:GridView>

When I the user clicks on "Save", another method named "LoadPersonFromFormControls" populates a Person object with the data from the form controls. Here is that method:

/// <summary>
/// Updates a passed Person object with data from the form controls.
/// </summary>
private void LoadPersonFromFormControls(Person passedPerson)
{
    passedPerson.FirstName = txtFirstName.Text.Trim();
    passedPerson.MiddleName = txtMiddleName.Text.Trim();
    passedPerson.LastName = txtLastName.Text.Trim();
    passedPerson.EmployeeID = txtEmployeeID.Text.Trim();
    passedPerson.SOMRelationshipType = LookupCodeManager.GetItem(int.Parse(ddlSOMRelationshipType.SelectedValue));
    passedPerson.DisabledFlg = cbDisabledFlg.Checked;
    passedPerson.PhoneNumbers = (EquatableList<PersonPhoneNumber>)gvPhoneNumbers.DataSource;
}

The problem is that "gvPhoneNumbers.DataSource" is null after postback. After some online reading, it is my understanding that the Gridview does not automatically "cache" it's dataset and the ability to reference it after postback is not possible unless the data is intentionally saved/cached by the developer in session or viewstate or some mechanism like that.

Now, I know that the gridview will remember it's data if I created an objectdatasource declaratively in the aspx page. The reason I didn't do that in the first place was because I didn't want to be getting the data twice; once in the code behind when the person Object was first instantiated and a second time when the objectdatasource fired.

So I am now considering moving to an objectdatasource only in the aspx page, and not setting the values in the codebehind at all. I was thinking I would make an object datasource for the entire Person object, and then bind a formview to it. Inside the formview would be my gvPhoneNumber gridview, which would have to be bound to one of the "sub values" inside the formview's datasource.

Is it possible to bind a gridview inside a formview to a subset of data from the formview's datasource? If so, how is that defined declaratively?

Also, do you think that going this route is worth it? Does anyone have other suggestions for solving this problem? I don't want to be retreiving the same data twice for each page load.

+1  A: 

When the page postback, you can retrieve the data from grid row and grid cells, right? Then use them to re-create the dataset or update the database. So you need to store the primary key in the dataset.

Estelle
I've done this recently also, so I can confirm this. You must ensure that `EnableViewState` is on for the `GridView` control, or you will be dealing with an empty row set upon postback.
Codesleuth
I set the EnableViewState to true but the GridView.Rows count is always zero on postback. Any other ideas?
Amanda Myer
A: 

Couple of thoughts.

Before you DataBind the GridView you want to check if(!PostBack) so that you don't over write the data in the GridView.

You Save logic should be in the OnClick event of your save button. Not in the Page_Load (if that's where it is already).

Greg B