【问题标题】:How to add an extra row (containing a Button and corresponding event handler) to the GridView如何向 GridView 添加额外的行(包含 Button 和相应的事件处理程序)
【发布时间】:2012-03-03 12:11:28
【问题描述】:

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

注意:分页行不适合放置此按钮,因为此自定义控件可用于分页错误的情况。同样,其他用途(例如总计)可能需要普通页脚。

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

    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 看起来都不错(与寻呼机行中的“工作”按钮一致。

有没有办法让我做到这一点,还是我在尝试不可能的事情?

【问题讨论】:

    标签: asp.net gridview


    【解决方案1】:

    创建页脚控件的最佳位置是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 添加到继承自 TablePagerTable 来为您的成本控制使用寻呼机。

    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;
        }
    }
    

    为了确保即使只显示一页也能看到分页器(注意如果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>
    

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

    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 ...
    }
    

    寻呼机方法中保持RowCreated 与上述相同。

    顶部/底部寻呼机的可见性将根据OriginalPagerPosition 属性在PreRender 中进行控制。即使使用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;
    }
    

    注意:如果要扩展 GridView 控件,则必须将所有出现的 GridView1(my test-grid) 替换为 this

    【讨论】:

    • 是的。去过也做过。事实上,要让它看起来不错,你必须先删除所有“多余”的单元格。 for (int i = e.Row.Cells.Count - 1; i &gt; 0; i--) { e.Row.Cells.RemoveAt(i); } 我有这个作为我的“现在要做的解决方案”。问题是,如果我需要将页脚用于其他目的怎么办? PagerRow 也位于页脚之后,我希望此按钮位于网格的最后一行。
    • 你可能有一个想法的开始。当不需要寻呼机时,需要做更多的工作来满足这种情况。我会玩这个,看看它是否会起作用。
    • @Fruitbar:请注意,如果不需要分页,则真正的分页器是不可见的。如果它是继承自 GridView 的自定义控件,您可以在 init-event 中简单地AllowPaging=true
    • 我认为这行不通。我想我可以跟踪 AllowPaging 和 PagerPosition 的原始值,这样按钮就不会干扰预期的寻呼机设置。但它总是以 AllowPaging=true 结束(大概是从 ViewState 重建的)。使用 4 个 GridView 对此进行测试:1) 无分页 2) 页面顶部 3) 页面底部 4) 页面顶部和底部。
    • @Fruitbat:你把我弄丢了。按钮以什么方式干扰?我的寻呼机方法按预期工作:No PagingPager Bottom_(default) 即使因为PageCount==1 而不需要分页也是如此。在 _Pager TopPager TopAndBottom 上,更新按钮将位于下一个 TableRow 的寻呼机控件下方。如果不希望这样做,您的具体要求是什么?
    【解决方案2】:

    在网格中添加额外的行很容易。但是您要求的困难在于 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...
        }
    }
    

    【讨论】:

    • 蒂姆,我认为这是一个折衷的解决方案(一个相当不错的折衷方案)。但是,我的目标是让这个按钮在自己的行中。如果你告诉我我想要的东西是不可能的,这是我能得到的最接近的东西,那么就足够公平了。如果你在这个答案的顶部加上那个意思的话,那么这将是一个可以接受的答案。
    • @Fruitbat:添加了几句话作为解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    相关资源
    最近更新 更多