سؤال

OK. I've long used this site as a reference, but I've now hit a wall of my own.

I am creating a custom server control which inherits from the System.Web.UI.WebControls.GridView class. It's purpose is simply to display a grid with a very defined format. It binds and loads the data fine, but trying to activate any of the paging throws an exception saying "Multiple controls with the same ID 'lblHdrText_2' were found. FindControl requires that controls have unique IDs.".

I could just throw the event out to the user and let them do the paging, but one of the goals was to have this control be able to handle its own paging, just like the GridView control already does.

I'm having the same problem for sorting and altering the page size as well. Basically anytime I call "DataBind" within the control after it has already been rendered.

Here's the code to handle those events:

    protected void OnFirstPageClicked(EventArgs e)
    {
        if (this.FirstPageClicked != null)
            this.FirstPageClicked.Invoke(this, e);

        GridViewPageEventArgs pgea = new GridViewPageEventArgs(0);
        this.OnPageIndexChanging(pgea);
        if (pgea.Cancel)
            return;

        this.PageIndex = 0;
        this.RefreshData();

        this.OnPageIndexChanged(e);
    }
    protected void OnLastPageClicked(EventArgs e)
    {
        if (this.LastPageClicked != null)
            this.LastPageClicked.Invoke(this, e);

        GridViewPageEventArgs pgea = new GridViewPageEventArgs(this.PageCount - 1);
        this.OnPageIndexChanging(pgea);
        if (pgea.Cancel)
            return;

        this.PageIndex = this.PageCount - 1;
        this.RefreshData();

        this.OnPageIndexChanged(e);
    }
    protected void OnPreviousPageClicked(EventArgs e)
    {
        if (this.PageIndex > 0)
        {
            if (this.PreviousPageClicked != null)
                this.PreviousPageClicked.Invoke(this, e);

            GridViewPageEventArgs pgea = new GridViewPageEventArgs(this.PageIndex++);
            this.OnPageIndexChanging(pgea);
            if (pgea.Cancel)
                return;

            this.PageIndex--;
            this.RefreshData();

            this.OnPageIndexChanged(e);
        }
    }
    protected void OnNextPageClicked(EventArgs e)
    {
        if (this.PageIndex < this.PageCount - 1)
        {

            if (this.NextPageClicked != null)
                this.NextPageClicked.Invoke(this, e);

            GridViewPageEventArgs pgea = new GridViewPageEventArgs(this.PageIndex++);
            this.OnPageIndexChanging(pgea);
            if (pgea.Cancel)
                return;

            this.PageIndex++;
            this.RefreshData();

            this.OnPageIndexChanged(e);
        }
    }
    protected void OnPageSizeChanged(EventArgs e)
    {
        this.RefreshData();
        if (this.PageSizeChanged != null)
            this.PageSizeChanged.Invoke(this, e);
    }
    protected override void OnDataBound(EventArgs e)
    {
        base.OnDataBound(e);
    }
    private void RefreshData()
    {
        this.DataBind();
    }
    private void imgPg_OnCommand(object sender, CommandEventArgs e)
    {
        switch (e.CommandName)
        {
            case "FirstPage":
                this.OnFirstPageClicked(EventArgs.Empty);
                break;
            case "LastPage":
                this.OnLastPageClicked(EventArgs.Empty);
                break;
            case "PrevPage":
                this.OnPreviousPageClicked(EventArgs.Empty);
                break;
            case "NextPage":
                this.OnNextPageClicked(EventArgs.Empty);
                break;
        }
    }
    private void drpPageSz_SelectedIndexChanged(object sender, EventArgs e)
    {
        DropDownList drpPgSz = (sender as DropDownList);

        if (drpPgSz != null)
        {
            this.PageSize = int.Parse(drpPgSz.SelectedValue);
            this.OnPageSizeChanged(e);
        }
        else
            throw new Exception("Unable to determine page size: cannot cast sender as DropDownList.");
    }

The actual event handlers are at the bottom. The "RefreshData" method is just there because I was experimenting with different ways of clearing the controls from the grid before I called "DataBind". So far, everything I've tried results in the entire grid not rendering after postback.

I am doing quite a bit with the Render and CreateChildControls, but the header generation itself is completely internal to the System.Web.UI.WebControls.GridView control. Here's my rendering code, if it helps at all:

    protected override void OnPreRender(EventArgs e)
    {
        Control link = this.Page.Header.FindControl("CustomGridViewCss");
        if (link == null)
        {
            System.Web.UI.HtmlControls.HtmlLink newLink = new System.Web.UI.HtmlControls.HtmlLink();
            newLink.ID = "CustomGridViewCss";
            newLink.Attributes.Add("href", this.Page.ClientScript.GetWebResourceUrl(typeof(ITCWebToolkit.Web.UI.Controls.GridView), "ITCWebToolkit.Web.UI.Controls.style.CustomGridView.css"));
            newLink.Attributes.Add("type", "text/css");
            newLink.Attributes.Add("rel", "stylesheet");
            this.Page.Header.Controls.Add(newLink);
        }

        base.OnPreRender(e);
        this.EnsureChildControls();
    }
    protected override void Render(HtmlTextWriter writer)
    {

        if (this._imgFPg != null)
            this.Page.ClientScript.RegisterForEventValidation(this._imgFPg.UniqueID);
        if (this._imgPrevPg != null)
            this.Page.ClientScript.RegisterForEventValidation(this._imgPrevPg.UniqueID);
        if (this._imgNextPg != null)
            this.Page.ClientScript.RegisterForEventValidation(this._imgNextPg.UniqueID);
        if (this._imgLastPg != null)
            this.Page.ClientScript.RegisterForEventValidation(this._imgLastPg.UniqueID);
        if (this._drpPageSz != null)
            this.Page.ClientScript.RegisterForEventValidation(this._drpPageSz.UniqueID);

        if (this.HeaderRow != null)
            for (int i = 1; i < this.HeaderRow.Cells.Count - 2; i++)
                if (i < this.Columns.Count && this.Columns[i] is SortableField && ((this.Columns[i] as SortableField).ShowSort))
                {
                    ImageButton img = (this.HeaderRow.Cells[i].FindControl("imgSort_" + i.ToString()) as ImageButton);
                    if (img != null)
                        this.Page.ClientScript.RegisterForEventValidation(img.UniqueID);
                }
        base.Render(writer);
    }
    protected override Table CreateChildTable()
    {
        this.PagerSettings.Visible = false;
        this.GridLines = GridLines.None;
        Table tbl = base.CreateChildTable();
        tbl.Attributes.Add("name", this.UniqueID);
        return tbl;
    }
    protected override int CreateChildControls(System.Collections.IEnumerable dataSource, bool dataBinding)
    {
        this.GridLines = GridLines.None;
        int iCount = base.CreateChildControls(dataSource, dataBinding);

        // Modify footer row
        System.Web.UI.WebControls.GridViewRow ftr = this.FooterRow;
        // NOTE: We're modifying the footer first, because we're looking at the
        //   total number of rows in the header for the ColSpan property we
        //   use in the footer and we want the row count *before* we modify
        //   the header.
        ftr.Cells.Clear();
        this.BuildFooter(this.FooterRow);

        // Modify Header Row
        System.Web.UI.WebControls.GridViewRow hdr = this.HeaderRow;
        hdr.CssClass = "GridViewHeader";

        for (int c = 0; c < hdr.Cells.Count; c++)
        {
            hdr.Cells[c].CssClass = "GridViewHeaderTC";
            if (c > 0)
                hdr.Cells[c].Style.Add("border-left", "solid 1px #ccccd3");

            if (c < this.Columns.Count && this.Columns[c] is SortableField && ((this.Columns[c] as SortableField).ShowSort))
            {
                hdr.Cells[c].Controls.Clear();

                Label lblHdrText = new Label();
                lblHdrText.ID = "lblHdrText_" + c.ToString();
                lblHdrText.Text = hdr.Cells[c].Text;
                hdr.Cells[c].Controls.Add(lblHdrText);

                ImageButton imgSort = new ImageButton();
                imgSort.ID = "imgSort_" + c.ToString();
                imgSort.CssClass = "GridViewHeaderSort";
                imgSort.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(typeof(ITCWebToolkit.Web.UI.Controls.GridView), "ITCWebToolkit.Web.UI.Controls.images.gridView.Sort.png");
                imgSort.AlternateText = "";
                imgSort.CommandArgument = (this.Columns[c] as BoundField).DataField;
                imgSort.CommandName = "Sort";
                imgSort.Command += new CommandEventHandler(this.imgSort_OnCommand);
                hdr.Cells[c].Controls.Add(imgSort);
                imgSort.Attributes.Add("name", imgSort.UniqueID);
            }
        }

        TableCell tdTL = new TableCell();
        tdTL.Style.Add(HtmlTextWriterStyle.Width, "6px");
        tdTL.CssClass = "GridViewHeaderTL";
        hdr.Cells.AddAt(0, tdTL);

        TableCell tdTR = new TableCell();
        tdTR.Style.Add(HtmlTextWriterStyle.Width, "6px");
        tdTR.Style.Add("border-left", "1px solid #ccccd3;");
        tdTR.CssClass = "GridViewHeaderTR";
        hdr.Cells.Add(tdTR);

        // Modify individual rows
        for (int i = 0; i < this.Rows.Count; i++)
        {
            System.Web.UI.WebControls.GridViewRow tr = this.Rows[i];
            tr.CssClass = (i % 2 == 0) ? "GridViewLineAlt" : "GridViewLine";

            for (int c = 0; c < tr.Cells.Count - 1; c++)
                tr.Cells[c].Style.Add("border-right", "solid 1px #ccccd3");

            TableCell tdL = new TableCell();
            tdL.CssClass = "GridViewLineLeft";
            tr.Cells.AddAt(0, tdL);

            TableCell tdR = new TableCell();
            tdR.CssClass = "GridViewLineRight";
            tr.Cells.Add(tdR);
        }

        return iCount;
    }
    protected void BuildFooter(GridViewRow tr)
    {
        TableCell tdBL = new TableCell();
        tdBL.Style.Add(HtmlTextWriterStyle.Width, "6px");
        tdBL.CssClass = "GridViewFooterBL";
        tr.Cells.Add(tdBL);

        int colCount = this.HeaderRow.Cells.Count;

        TableCell td = new TableCell();
        td.ID = "tdFooterControls";
        td.CssClass = "GridViewFooterBC";
        td.ColumnSpan = colCount;

        this._spanPgBtns = new Label();
        this._spanPgBtns.ID = "spanPgButtons";
        this._spanPgBtns.Style.Add("float", "right");
        this._spanPgBtns.Style.Add("margin-right", "20px");

        this._imgFPg = new ImageButton();
        this._imgFPg.ID = "imgFPg";
        this._imgFPg.CssClass = "FirstPg";
        this._imgFPg.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(typeof(ITCWebToolkit.Web.UI.Controls.GridView), "ITCWebToolkit.Web.UI.Controls.images.gridView.FstPg.png");
        this._imgFPg.ImageAlign = ImageAlign.Middle;
        this._imgFPg.CommandName = "FirstPage";
        this._imgFPg.Command += new CommandEventHandler(this.imgPg_OnCommand);
        this._spanPgBtns.Controls.Add(this._imgFPg);

        this._imgPrevPg = new ImageButton();
        this._imgPrevPg.ID = "imgPrevPg";
        this._imgPrevPg.CssClass = "PrevPg";
        this._imgPrevPg.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(typeof(ITCWebToolkit.Web.UI.Controls.GridView), "ITCWebToolkit.Web.UI.Controls.images.gridView.PrevPg.png");
        this._imgPrevPg.ImageAlign = ImageAlign.Middle;
        this._imgPrevPg.CommandName = "PrevPage";
        this._imgPrevPg.Command += new CommandEventHandler(this.imgPg_OnCommand);
        this._spanPgBtns.Controls.Add(this._imgPrevPg);

        Label lblPageNum = new Label();
        lblPageNum.ID = "lblPageNum";
        lblPageNum.Width = new Unit("50px");
        lblPageNum.Text = string.Format("{0} / {1}", this.PageIndex + 1, this.PageCount);
        lblPageNum.Style.Add(HtmlTextWriterStyle.TextAlign, "center");
        this._spanPgBtns.Controls.Add(lblPageNum);

        this._imgNextPg = new ImageButton();
        this._imgNextPg.ID = "imgNextPg";
        this._imgNextPg.CssClass = "NextPg";
        this._imgNextPg.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(typeof(ITCWebToolkit.Web.UI.Controls.GridView), "ITCWebToolkit.Web.UI.Controls.images.gridView.NextPg.png");
        this._imgNextPg.ImageAlign = ImageAlign.Middle;
        this._imgNextPg.CommandName = "NextPage";
        this._imgNextPg.Command += new CommandEventHandler(this.imgPg_OnCommand);
        this._spanPgBtns.Controls.Add(this._imgNextPg);

        this._imgLastPg = new ImageButton();
        this._imgLastPg.ID = "imgLastPg";
        this._imgLastPg.CssClass = "LastPg";
        this._imgLastPg.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(typeof(ITCWebToolkit.Web.UI.Controls.GridView), "ITCWebToolkit.Web.UI.Controls.images.gridView.LstPg.png");
        this._imgLastPg.ImageAlign = ImageAlign.Middle;
        this._imgLastPg.CommandName = "LastPage";
        this._imgLastPg.Command += new CommandEventHandler(this.imgPg_OnCommand);
        this._spanPgBtns.Controls.Add(this._imgLastPg);

        td.Controls.Add(this._spanPgBtns);

        Label spanPageSz = new Label();
        spanPageSz.ID = "spanPageSz";
        spanPageSz.Style.Add("margin-left", "20px");

        this._drpPageSz = new DropDownList();
        this._drpPageSz.ID = "drpPageSzSelect";
        this._drpPageSz.AutoPostBack = true;
        this._drpPageSz.SelectedIndexChanged += new EventHandler(drpPageSz_SelectedIndexChanged);
        this._drpPageSz.Items.Add(new ListItem("10", "10"));
        this._drpPageSz.Items.Add(new ListItem("25", "25"));
        this._drpPageSz.Items.Add(new ListItem("50", "50"));
        this._drpPageSz.Items.Add(new ListItem("100", "100"));
        spanPageSz.Controls.Add(this._drpPageSz);
        td.Controls.Add(spanPageSz);

        Label lblRecVis = new Label();
        lblRecVis.ID = "lblRecordsCount";
        lblRecVis.Style.Add("margin-left", "20px");
        lblRecVis.Text = string.Format("Displaying {0} of {1} records.", Math.Min(this.PageSize, this.Rows.Count - (this.PageIndex * this.PageSize)), this.Rows.Count);
        lblRecVis.Text = "Total Record Display";
        td.Controls.Add(lblRecVis);
        tr.Cells.Add(td);

        TableCell tdBR = new TableCell();
        tdBR.Style.Add(HtmlTextWriterStyle.Width, "6px");
        tdBR.CssClass = "GridViewFooterBR";
        tr.Cells.Add(tdBR);

        this._imgFPg.Attributes.Add("name", this._imgFPg.UniqueID);
        this._imgPrevPg.Attributes.Add("name", this._imgPrevPg.UniqueID);
        this._imgNextPg.Attributes.Add("name", this._imgNextPg.UniqueID);
        this._imgLastPg.Attributes.Add("name", this._imgLastPg.UniqueID);
        this._drpPageSz.Attributes.Add("name", this._drpPageSz.UniqueID);
    }

I'm only about 6/10 on custom server controls, so I'm sure there's at least one thing I'm doing wrong here :)

Thanks in advance for any help!

هل كانت مفيدة؟

المحلول

OK. I finally found a reference and answered my own question. The trick is in overriding the "PerformSelect" method and handling DataSource vs DataSourceID there.

Details on how to do this can be found on this MSDN page:

http://msdn.microsoft.com/en-us/library/ms366539(v=vs.90).aspx

Look for the section titled "Initiate Data Retrieval" a little over half-way down.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top