Wrox Programmer Forums
|
ASP.NET 1.x and 2.0 Application Design Application design with ASP.NET 1.0, 1.1, and 2.0.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the ASP.NET 1.x and 2.0 Application Design section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old March 12th, 2004, 11:52 AM
Registered User
 
Join Date: Mar 2004
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
Default "Where do all the DataItems go??"

I have a datagrid. Its DataSource is an ArrayList of objects; each one has an int ID, strings for name and description. I have inline editing for the rows. When I click an update button, what I want to have happen is for the change to get committed to the database. Simple. That part I've done.

However, the name field (input via a text box) needs to be validated with a CustomValidator, which involves some codebehind which queries the database to see whether the name entered in the textbox is unique in the database.

The update-this-row click causes a postback. The button has CausesValidation set to "true". The Validator is as follows:

Code:
protected void ValidateSectionName(object source, ServerValidateEventArgs args) {
    // TODO: BUG: figure out where DataItems go on postback
    DataGridItem dgi = dgSections.Items[ dgSections.EditItemIndex ]; // item being edited
    Section s = (Section)dgi.DataItem;
    TextBox tbName = (TextBox)dgi.FindControl("tbName");
    args.IsValid = s.IsUniqueName(tbName.Text.Trim());
}
This is the DataGrid declaration I'm working within (sans extraneous-to-discussion columns, for clarity):

Code:
<asp:DataGrid ID="dgSections" Runat="server" AutoGenerateColumns="False" EnableViewState="true" DataKeyField="ID" GridLines="None" cssclass="dg" AllowSorting="True">
    <Columns>
        <asp:TemplateColumn ItemStyle-CssClass="dg_iconcol" HeaderStyle-CssClass="dg_header_iconcol">
            <ItemTemplate>
                <asp:ImageButton Runat="server" Tooltip="Click to edit section"
                    ImageUrl="~/images/icons/edit.gif" CommandName="Edit" height="20" width="20" AlternateText="Edit section"
                    CommandArgument='<%# DataBinder.Eval(Container.DataItem, "ID") %>'
                    Visible='<%# CurrentUser.HasPermission(new Permissions[] { Permissions.DLS_EditSection, Permissions.Core_LinkGroup_Section }) %>' />
            </ItemTemplate>
        </asp:TemplateColumn>

        <asp:TemplateColumn ItemStyle-CssClass="dg_iconcol" HeaderStyle-CssClass="dg_header_iconcol">
            <ItemTemplate>
                <asp:ImageButton ID="ibtnCancel" ImageUrl="~/images/icons/cancel.gif" tooltip="Click to cancel edit." Runat="server" CausesValidation="False" AlternateText="Cancel edit"
                    CommandName="Cancel" CommandArgument='<%# DataBinder.Eval(Container.DataItem, "ID") %>' />
            </ItemTemplate>
        </asp:TemplateColumn>

        <asp:TemplateColumn ItemStyle-CssClass="dg_iconcol" HeaderStyle-CssClass="dg_header_iconcol">
            <ItemTemplate>
                <asp:ImageButton ID="ibtnSave" ImageUrl="~/images/icons/ok.gif" tooltip="Click to save changes." Runat="server" CausesValidation="False" AlternateText="Save changes"
                    CommandName="Update" CommandArgument='<%# DataBinder.Eval(Container.DataItem, "ID") %>' />
            </ItemTemplate>
        </asp:TemplateColumn>

        <asp:TemplateColumn HeaderText="Name" SortExpression="Name">
            <ItemTemplate>
                <%# DataBinder.Eval(Container.DataItem, "Name") %><input type="hidden" id="iTimeStamp" runat="server" value='<%# Convert.ToDateTime(DataBinder.Eval(Container.DataItem, "stamp")).ToString() %>' />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:TextBox ID="tbName" Runat="server" CssClass="tb" MaxLength="50" Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' /><input type="hidden" id="iTimeStamp" runat="server" value='<%# Convert.ToDateTime(DataBinder.Eval(Container.DataItem, "stamp")).ToString() %>' />
                <asp:RequiredFieldValidator ID="rfvalName" runat="server" Display="None" ErrorMessage="You must supply a section name." ControlToValidate="tbName" />
                <asp:RegularExpressionValidator ID="revalName" Runat="server" Display="None" ErrorMessage="The section name must be between 1 and 50 characters long." ControlToValidate="tbName" ValidationExpression="^.{1,30}$" />
                <asp:CustomValidator Runat="server" Display="None" ErrorMessage="The section name must be unique - the one you entered already exists in the database." OnServerValidate="ValidateSectionName" />
            </EditItemTemplate>
        </asp:TemplateColumn>

        <asp:TemplateColumn HeaderText="Description" SortExpression="Description">
            <ItemTemplate>
                <%# (DataBinder.Eval(Container.DataItem, "Description").ToString() == "")? "&nbsp;": DataBinder.Eval(Container.DataItem, "Description").ToString() %>
            </ItemTemplate>
            <EditItemTemplate>
                <asp:TextBox ID="tbDescription" Runat="server" CssClass="tb" MaxLength="500" Text='<%# DataBinder.Eval(Container.DataItem, "Description") %>' Rows="3" TextMode="MultiLine" />
            </EditItemTemplate>
        </asp:TemplateColumn>

    </Columns>
    </asp:DataGrid>
Note ViewState is turned on.

This is my Page_Load(), and populate(mode):

Code:
private void Page_Load(object sender, System.EventArgs e) {
    if (!IsPostBack) {
        PFPPage.StoreBack(Session, Request.UrlReferrer);
        populate(PopulateMode.View);
    }
}

private void populate(PopulateMode mode) {
    SortExpression = (Session["SortExpression"] == null)? "name" : Session["SortExpression"].ToString();
    SortAsc = (Session["SortAsc"] == null)? true : Convert.ToBoolean(Session["SortAsc"]);
    SectionList[] sl = Section.GetSections(CurrentUser,
        pnlFilterControls.Visible? tbCriteria.Text.Trim(): "", 
        pnlFilterControls.Visible? cblFields.Items[0].Selected: false, 
        pnlFilterControls.Visible? cblFields.Items[1].Selected: false, 
        pnlFilterControls.Visible? cblFields.Items[2].Selected: false,
        SortExpression,
        SortAsc);
    if (sl[0].Count > 0 || mode != PopulateMode.View) {
        lblNoData.Visible = false;
        dgSections.Visible = true;
        switch (mode) {
            case PopulateMode.View:
                dgSections.AllowSorting = true;
                dgSections.DataSource = sl[0];
                dgSections.DataBind();
                btnCreate.Enabled = CurrentUser.HasPermission(Permissions.DLS_EditSection);
                dgSections.Columns[0].Visible = true;
                dgSections.Columns[1].Visible = true;
                dgSections.Columns[2].Visible = true;
                dgSections.Columns[3].Visible = false;
                dgSections.Columns[4].Visible = false;
                dgSections.Columns[5].Visible = false;
                dgSections.Columns[6].Visible = false;
                dgSections.Columns[7].Visible = false;
                dgSections.Columns[8].Visible = true;
                btnCreate.Enabled = true;
                break;
            case PopulateMode.Insert:
                Section s = new Section();
                s.Name = "Enter name of new section here (required)...";
                sl[0].Insert(0, s);
                dgSections.EditItemIndex = 0;
                goto case PopulateMode.Edit; // fall through, since insert is just a special case of edit...
            case PopulateMode.Edit:
                dgSections.AllowSorting = false;
                dgSections.DataSource = sl[0];
                dgSections.DataBind();
                dgSections.Columns[0].Visible = false;
                dgSections.Columns[1].Visible = false;
                dgSections.Columns[2].Visible = false;
                dgSections.Columns[3].Visible = false;
                dgSections.Columns[4].Visible = false;
                dgSections.Columns[5].Visible = false;
                dgSections.Columns[6].Visible = true;
                dgSections.Columns[7].Visible = true;
                dgSections.Columns[8].Visible = true;
                btnCreate.Enabled = false;
                break;
        }
    } else {
        lblNoData.Visible = true;
        dgSections.Visible = false;
    }
}
My question? Why is my DataSource null inside of the Validator's OnServerValidate?!

Note that I realise I can get around this by not using a CustomValidator, and instead calling the IsUniqueName function elsewhere (like inside of the DataGrid's ItemCommand event, where I have a switch statement that does different things depending on what the commandname is) just before I persist back to the database, but I feel that's cheating...

 
Old March 12th, 2004, 11:53 AM
Registered User
 
Join Date: Mar 2004
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Oh. Bugger. Sorry about the really-really wide {code} blocks.

 
Old March 12th, 2004, 12:17 PM
Imar's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 17,089
Thanks: 80
Thanked 1,576 Times in 1,552 Posts
Default

Yeah, no problem. Just switched to 2048 x 1536 and it looks fine ;)

Kidding aside, I am not sure what the problem is. Can you elaborate a bit more on what you're trying to do?
Are you loosing the grid's values on PostBack / validation?

I think that for a DataGrid the DataSource is not cached in ViewState (that would cause too much overhead). I think you'll need to rebind the grid in IsPostBack as well, and then check the Grid for its values....

Imar

(You may want to start a new thread for this, with smaller code. Makes it a bit easier to read and edit in this thread).

---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
 
Old March 12th, 2004, 01:20 PM
Registered User
 
Join Date: Mar 2004
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I read http://authors.aspalliance.com/JimRo...etPartTwo.aspx and his solution to almost-my-problem is to populate the DataSource unconditionally of IsPostBack, but only bind it under certain conditions - at the moment I'm playing with that with a simpler DataGrid. I'll let you know how I get on.

 
Old March 15th, 2004, 01:10 PM
planoie's Avatar
Friend of Wrox
 
Join Date: Aug 2003
Posts: 5,407
Thanks: 0
Thanked 16 Times in 16 Posts
Default

What's the point of populating the data source every time if you don't bind it?

My understanding is that the datagrid does maintain some form of the data in it's own viewstate. It probably doesn't maintain the whole object that was set to the datasource, but it does maintain all the columsn to some extent. This is evident by the fact that you don't need to load a grid every time the page runs, the grid will restore itself from viewstate. You just need to rebind when you change the state of the grid (i.e. SelectedIndex; EditIndex; PageIndex etc)

Peter
------------------------------------------------------
Work smarter, not harder.
 
Old March 16th, 2004, 04:33 AM
Registered User
 
Join Date: Mar 2004
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I need the DataSource because I'm binding to an ArrayList of objects. I use inline editing. I have a custom validator (ie, needs a postback) on one of the editable fields, which calls a public method on the row's object and goes off to check the database to see if the input's ok.

Thus, I need the DataSource to be populated on every postback, whether that postback is caused by the grid itself or some other control on the page (of which there are several). But the validator does not need the grid to be rebound - I get the object I want with ((ArrayList)grid.DataSource)[grid.EditItemIndex] (roughly).

Unless I'm being stupid (it's happened before! ;) ), I don't see another way to do it except by removing the need for the call to populate in my validator, by putting the code from my validator into my update grid event handler, and have it stop being a validator, but just a random bit of code - in which case it won't hook up with my validation summary and I'd have to hack *that*.










Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.