如何将额外的行(包含Button和相应的事件处理程序)添加到GridView

时间:2012-03-03 12:11:29

标签: asp.net gridview

这一定是很多人都做过的事情。基本上,它是一个自定义GridView(即继承控件),能够一次更新所有行。我已经尝试将“全部更新”按钮放在不同的位置(页脚,寻呼机,网格外),但当按钮位于GridView的最后一行的额外行时,它看起来最好(对我而言)。 p>

注意:寻呼机行不适合此按钮,因为此自定义控件可用于分页为假的情况。同样,正常的页脚也可能需要用于其他目的(例如总数)。

这是我将按钮放在正确位置的代码(对于简洁变量等道歉):

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        //Add an extra row to the table...
        if (_updateAllEnabled)
        {
          GridViewRow r = base.CreateRow(-1, -1, DataControlRowType.Footer, DataControlRowState.Normal);
          Button btn = new Button();
          TableCell c = new TableCell();
          btn.ID = "UpdateAllButton";    // tried with and without this line
          btn.Text = "Update All";
          btn.Click += new EventHandler(UpdateAll);
          r.Cells.Add(c);
          c.Controls.Add(btn);
          Table t = this.Controls[0] as Table;
          c.ColumnSpan = this.Columns.Count;
          t.Rows.Add(r);           
      }
    }

这给出了我想要的外观,但点击事件(UpdateAll)不会触发。

我认为这些东西在生命周期中被添加得太晚(PreRender),但我还能在哪里做到这一点以确保该行位于GridView的末尾?我还认为识别按钮可能有问题,所以我尝试设置ID。在任何情况下,生成的HTML中的ID看起来都很正常(与寻呼机行中的“工作”按钮一致。

我有没有办法实现这一目标,还是我尝试了不可能的事情?

2 个答案:

答案 0 :(得分:2)

创建页脚控件的最佳位置是RowCreated,因为这在生命周期中足够早,并且还确保在每次回发时重新创建它们:

页脚方法

protected void Grid_RowCreated(Object sender, GridViewRowEventArgs e) {
    if(e.Row.RowType == DataControlRowType.Footer) {
        Button btn = new Button();
        TableCell c = new TableCell();
        btn.ID = "UpdateAllButton";   
        btn.Text = "Update All";
        btn.Click += new EventHandler(UpdateAll);
        var firstCell=e.Row.Cells[0];
        firstCell.ColumnSpan =e.Row.Cells.Count;
        firstCell.Controls.Add(btn);
        while(e.Row.Cells.Count > 1)e.Row.Cells.RemoveAt(e.Row.Cells.Count-1);
    }
}

当然,您必须将ShowFooter设置为true

<asp:GridView ID="GridView1" 
     ShowFooter="true" 
     OnRowCreated="Grid_RowCreated" 
     runat="server"
</asp:GridView>

寻呼机方法:

在我看来,这是FooterRow的目的。但是如果你真的想确保你的Button位于GridView的最后一行(甚至低于Pager评论),我会尝试我的下一个方法。

此处我通过向TableRow添加另一个PagerTable来使用寻呼机进行费用控制,该protected void Grid_RowCreated(Object sender, GridViewRowEventArgs e) { switch(e.Row.RowType){ case DataControlRowType.Pager: Button btnUpdate = new Button(); btnUpdate.ID = "UpdateButton"; btnUpdate.Text = "Update"; btnUpdate.Click += new EventHandler(UpdateAll); var tblPager = (Table)e.Row.Cells[ 0 ].Controls[ 0 ]; var row = new TableRow(); var cell = new TableCell(); cell.ColumnSpan = tblPager.Rows[ 0 ].Cells.Count; cell.Controls.Add(btnUpdate); row.Cells.Add(cell); tblPager.Rows.Add(row); break; } } 继承自Table

PageSize==1

确保即使只显示一个页面也能看到寻呼机(请注意,protected void Grid_PreRender(object sender, EventArgs e){ GridView gv = (GridView)sender; GridViewRow gvr = (GridViewRow)gv.BottomPagerRow; if(gvr != null) { gvr.Visible = true; var tblPager = (Table)gvr.Cells[ 0 ].Controls[ 0 ]; //hide real pager if unnecessary tblPager.Rows[ 0 ].Visible = GridView1.PageCount > 1; } } 时真正的寻呼机是不可见的):

AllowPaging=true

当然,您必须设置<asp:GridView ID="GridView1" AllowPaging="true" PagerSettings-Mode="NumericFirstLast" OnRowCreated="Grid_RowCreated" OnPreRender="Grid_PreRender" OnPageIndexChanging="Grid_PageChanging" runat="server"> </asp:GridView>

public PagerPosition OriginalPagerPosition{
    get { return (PagerPosition)ViewState[ "OriginalPagerPosition" ]; }
    set { ViewState[ "OriginalPagerPosition" ] = value; }
}

protected void Page_Load(object sender, EventArgs e){
    if(!IsPostBack) OriginalPagerPosition = GridView1.PagerSettings.Position;
    GridView1.PagerSettings.Position = PagerPosition.TopAndBottom;
    GridView1.AllowPaging = true;

    // databinding stuff ...
}

最终方法(适用于自定义GridView和所有PagerPositions):

RowCreated

寻呼机方式中保持PreRender与上述相同。

根据OriginalPagerPosition属性,将在PagerPosition=TOP中控制顶部/底部寻呼机的可见性。即使使用protected void Grid_PreRender(object sender, EventArgs e) { GridView gv = (GridView)sender; GridViewRow tpr = (GridViewRow)gv.TopPagerRow; GridViewRow bpr = (GridViewRow)gv.BottomPagerRow; tpr.Visible = gv.PageCount > 1 && (OriginalPagerPosition == PagerPosition.Top || OriginalPagerPosition == PagerPosition.TopAndBottom); bpr.Visible = true; var tblBottomPager = (Table)bpr.Cells[ 0 ].Controls[ 0 ]; tblBottomPager.Rows[ 0 ].Visible = gv.PageCount > 1 && (OriginalPagerPosition == PagerPosition.Bottom || OriginalPagerPosition == PagerPosition.TopAndBottom); var tblTopPager = (Table)tpr.Cells[ 0 ].Controls[ 0 ]; tblTopPager.Rows[1].Visible = false; } 也会创建两个寻呼机,您的附加控件需要底部寻呼机:

GridView1

注意:如果要扩展GridView控件,则必须用this替换{{1}}(我的测试网格)的所有出现。

答案 1 :(得分:1)

在网格中添加额外的行很容易。但是你的要求的难点在于GridView的RowCollection不应该包含这一行,因为这容易出错。即使启用了分页,它也应该是最后一行。这是(afaik)不可能的。

因此我选择使用此功能扩展寻呼机。

我将此作为单独的答案添加,因为我的另一个已经过于详细,并描述了两种不同的方式(页脚,寻呼机)将控件添加到GridView而不扩展它。

此方法根据您自己的要求扩展GridView,与我的其他寻呼机方法类似。但它更干净,只会在BottomPager添加额外的行。它也适用于每个设置(AllowPaging = false,Pager-Position:Top,Bottom,BottomTop):

[DefaultProperty("EnableUpdateAll")]
[ToolboxData("<{0}:UpdateGridView runat=server></{0}:UpdateGridView>")]
public class UpdateGridView : GridView
{
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue("true")]
    [Localizable(true)]
    public bool EnableUpdateAll
    {
        get
        {
            Object val = ViewState["EnableUpdateAll"];
            return ((val == null) ? true : (bool)val);
        }

        set
        {
            ViewState["EnableUpdateAll"] = value;
        }
    }

    private bool OriginalAllowPaging
    {
        get
        {
            Object val = ViewState["OriginalAllowPaging"];
            return (bool)val;
        }

        set
        {
            ViewState["OriginalAllowPaging"] = value;
        }
    }

    private PagerPosition OriginalPagerPosition
    {
        get
        {
            Object val = ViewState["OriginalPagerPosition"];
            return (PagerPosition)val;
        }

        set
        {
            ViewState["OriginalPagerPosition"] = value;
        }
    }

    protected override void OnInit(System.EventArgs e)
    {
        if (ViewState["OriginalPagerPosition"] == null)
            OriginalPagerPosition = base.PagerSettings.Position;
        if(OriginalPagerPosition != PagerPosition.Bottom)
            PagerSettings.Position=PagerPosition.TopAndBottom;
        if (ViewState["OriginalAllowPaging"] == null)
            OriginalAllowPaging = base.AllowPaging;
        base.AllowPaging = true;
    }

    protected override void OnRowCreated(GridViewRowEventArgs e)
    {
        switch (e.Row.RowType)
        {
            case DataControlRowType.Pager:
                //check if we are in BottomPager
                if (this.Rows.Count != 0 && this.EnableUpdateAll)
                {
                    Button btnUpdate = new Button();
                    btnUpdate.ID = "BtnUpdate";
                    btnUpdate.Text = "Update";
                    btnUpdate.Click += new EventHandler(UpdateAll);
                    var tblPager = (Table)e.Row.Cells[0].Controls[0];
                    var row = new TableRow();
                    var cell = new TableCell();
                    cell.ColumnSpan = tblPager.Rows[0].Cells.Count;
                    cell.Controls.Add(btnUpdate);
                    row.Cells.Add(cell);
                    tblPager.Rows.Add(row);
                }
                break;
        }
    }

    protected override void OnPreRender(EventArgs e)
    {
        bool bottomPagerVisible = 
            OriginalAllowPaging && 
            PageCount > 1 && 
            (OriginalPagerPosition == PagerPosition.Bottom || OriginalPagerPosition == PagerPosition.TopAndBottom);
        BottomPagerRow.Visible = bottomPagerVisible || EnableUpdateAll;
        var tblBottomPager = (Table)BottomPagerRow.Cells[0].Controls[0];
        tblBottomPager.Rows[0].Visible = bottomPagerVisible;
    }

    private void UpdateAll(Object sender, EventArgs e)
    {
        // do something...
    }
}