Dynamically generate page linkbuttons for the PagerTemplate of a GridView - c#

From the MSDN page for the PagerTemplate of the GridView control (emphasis mine):
Typically, button controls are added to the pager template to perform the paging operations. The GridView control performs a paging operation when a button control with its CommandName property set to "Page" is clicked. The button's CommandArgument property determines the type of paging operation to perform.
"Next": Navigates to the next page.
"Prev": Navigates to the previous page.
"First": Navigates to the first page.
"Last": Navigates to the last page.
Integer value: Navigates to the specified page number.
Source: http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.pagertemplate(v=vs.110).aspx
This stuff is pretty straightforward for the next/prev/first/last buttons because of their static nature.
<PagerTemplate>
<table>
<tr>
<td>
<asp:Button CommandName="Page" CommandArgument="First" Enabled="<%# Model.PageContext.HasPrevious %>" Text="First" runat="server" />
</td>
<td>
<asp:Button CommandName="Page" CommandArgument="Prev" Enabled="<%# Model.PageContext.HasPrevious %>" Text="Previous" runat="server" />
</td>
<td>
<asp:Button CommandName="Page" CommandArgument="Next" Enabled="<%# Model.PageContext.HasNext %>" Text="Next" runat="server" />
</td>
<td>
<asp:Button CommandName="Page" CommandArgument="Last" Enabled="<%# Model.PageContext.HasNext %>" Text="Last" runat="server" />
</td>
</tr>
</table>
</PagerTemplate>
On the other hand, the CommandArgument for numeric buttons has to be dynamic and unique for each page that can be navigated to. I'm guessing I will need a for-loop or a repeater control to get the right number of page links on the user's display.
Nothing I've tried seems to just work. My for-loop code doesn't even compile.
<% for (int pageIndex = 0; pageIndex < Model.PageContext.PageCount; pageIndex++) { %>
<asp:LinkButton CommandName="Page" CommandArgument="<%= pageIndex %>" Text="<%= pageIndex + 1 %>" runat="server"/>
<% } %>
My alternative approach uses a Repeatercontrol and does compile, but the Repeatercontrol itself handles the ItemCommand for each button, preventing the "Page" ItemCommand events from bubbling up to the GridView.
<asp:Repeater ItemType="System.Int32" SelectMethod="GetPages" runat="server">
<ItemTemplate>
<asp:LinkButton CommandName="Page" CommandArgument="<%# Item %>" Text="<%# Item + 1 %>" runat="server" />
</ItemTemplate>
</asp:Repeater>
Each button raises the correct event, but the events never reach the GridView because they are handled at a lower level by the Repeater control. I have to attach an event handler that listens for RepeaterCommandEventArgs and then set the new page index on the GridView myself.
*Takes deep breath*
Can I add numeric page buttons without having to wire up events myself?
The result that I'm trying to achieve, based on the code above:

I found an even simpler way, one that is framework 4.0 compatible
<asp:GridView ID="GridView_History" runat="server">
<PagerTemplate>
<asp:LinkButton ID="lnkPrev" runat="server" CommandName="Page" CommandArgument="Prev">Prev</asp:LinkButton>
<asp:Repeater ID="rptPagesHistory" OnItemDataBound="rptPagesHistory_ItemDataBound" runat="server" OnLoad="rptPagesHistory_Load">
<ItemTemplate>
<asp:LinkButton ID="lnkPageNumber" CommandName="Page" runat="server" OnClick="lnkPageNumberHistory_Click" />
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="lnkNext" runat="server" CommandName="Page" CommandArgument="Next">Next</asp:LinkButton>
</PagerTemplate>
</asp:GridView>
protected void rptPagesHistory_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
LinkButton lnkPageNumber = new LinkButton();
System.Int32 pageNumber = (System.Int32)e.Item.DataItem;
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
lnkPageNumber = (LinkButton)e.Item.FindControl("lnkPageNumber");
lnkPageNumber.Text = pageNumber;
lnkPageNumber.CommandArgument = pageNumber - 1;
}
}
protected void rptPagesHistory_Load(object sender, EventArgs e)
{
Repeater rpt = (Repeater)sender;
rpt.DataSource = Enumerable.Range(1, GridView_History.PageCount);
rpt.DataBind();
}
protected void lnkPageNumberHistory_Click(object sender, EventArgs e)
{
LinkButton btn = (LinkButton)sender;
GridView_History.PageIndex = btn.CommandArgument;
GridView_History.DataBind();
}

I figured out a way to get it done using the Repeater control.
First, populate the repeater with link buttons for each page index (1-based) and attach an event handler for the OnItemCommand event.
<asp:Repeater runat="server" ItemType="System.Int32" SelectMethod="GetPages" OnItemCommand="OnRepeaterCommand">
<ItemTemplate>
<asp:LinkButton CommandName="Page" CommandArgument="<%# Item %>" Text="<%# Item %>" runat="server" />
</ItemTemplate>
</asp:Repeater>
Pay special attention to how I'm binding my repeater to the collection of int that is returned by GetPages.
public IEnumerable<int> GetPages()
{
return Enumerable.Range(1, this.PageCount);
}
Finally, in the event handler, re-insert the CommandEventArgs into the event pipeline using some reflection-fu.
protected void OnRepeaterCommand(object source, RepeaterCommandEventArgs e)
{
source.GetType()
.GetMethod("RaiseBubbleEvent", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(source, new[]
{
e.CommandSource,
new CommandEventArgs(e.CommandName, e.CommandArgument)
});
}
That's it. You don't have to do anything else. The GridView will handle the ItemCommand and set the page index to the new value.

Here is the code, lifted right from the page(s).
<asp:GridView ID="grdUsage" PageSize="20" Width="100%" runat="server" AllowPaging="True" AllowSorting="False" CellPadding="4" ForeColor="#333333" GridLines="None" Font-Size="14px" Font-Bold="false" OnPageIndexChanging="grdUsage_PageIndexChanging" OnRowDataBound="grdUsage_RowDataBound" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="ID" HeaderStyle-HorizontalAlign="Center" ItemStyle-Width="100px" ItemStyle-Font-Size="12px">
<ItemTemplate>
<asp:Literal ID="lCampaignID" runat="server"></asp:Literal>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderStyle-HorizontalAlign="Left">
<ItemTemplate>
<asp:HyperLink ID="lnkCampaign" runat="server" Target="_blank" Font-Size="12px"></asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<EditRowStyle BackColor="#2461BF" />
<FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" HorizontalAlign="Left" />
<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#EFF3FB" />
<SelectedRowStyle BackColor="#D1DDF1" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
<AlternatingRowStyle BackColor="White" />
<PagerStyle HorizontalAlign="Center" BackColor="white" />
<PagerTemplate>
<ul class="pagination">
<li>
<asp:LinkButton ID="lnkPrev" runat="server" CommandName="Page" CommandArgument="Prev"><span>«</span></asp:LinkButton></li>
<asp:Repeater ID="rptPagesUsage" OnItemDataBound="rptPagesUsage_ItemDataBound" runat="server" OnLoad="rptPagesUsage_Load">
<ItemTemplate>
<asp:Literal ID="lListItem" runat="server"><li></asp:Literal><asp:LinkButton ID="lnkPageNumber" CommandName="Page" runat="server" OnClick="lnkPageNumberUsage_Click" /></li>
</ItemTemplate>
</asp:Repeater>
<li>
<asp:LinkButton ID="lnkNext" runat="server" CommandName="Page" CommandArgument="Next"> <span>»</span></asp:LinkButton></li>
</ul>
</PagerTemplate>
</asp:GridView>
Sub pGrid(sql as string) '
grdUsage.DataSource = G_GetDataTable(sql)
grdUsage.DataBind()
If grdUsage.Rows.Count > 0 Then
grdUsage.HeaderRow.Cells(1).Text = String.Format("Associated Campaigns for: <i>{0}</i>", txtEMailTitle.Text)
End If
End Sub
Protected Sub rptPagesUsage_Load(sender As Object, e As EventArgs)
Dim rpt As Repeater = DirectCast(sender, Repeater)
rpt.DataSource = Enumerable.Range(1, grdUsage.PageCount)
rpt.DataBind()
End Sub
Protected Sub rptPagesUsage_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)
Dim lListItem As New Literal()
Dim lnkPageNumber As New LinkButton()
Dim pageNumber As System.Int32 = DirectCast(e.Item.DataItem, System.Int32)
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
lListItem = DirectCast(e.Item.FindControl("lListItem"), Literal)
lnkPageNumber = DirectCast(e.Item.FindControl("lnkPageNumber"), LinkButton)
lnkPageNumber.Text = pageNumber
lnkPageNumber.CommandArgument = pageNumber - 1
If e.Item.ItemIndex = grdUsage.PageIndex Then
lListItem.Text = "<li class=""active"">"
End If
End If
End Sub
Protected Sub grdUsage_PageIndexChanging(sender As Object, e As GridViewPageEventArgs)
hSelectedTab.Value = 5
If e.NewPageIndex >= 0 Then
grdUsage.PageIndex = e.NewPageIndex
pGrid(sql)
End If
End Sub
Protected Sub grdUsage_RowDataBound(sender As Object, e As GridViewRowEventArgs)
Dim drview As DataRowView = DirectCast(e.Row.DataItem, DataRowView)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim lnkCampaign As HyperLink = DirectCast(e.Row.FindControl("lnkCampaign"), HyperLink)
Dim lCampaignID As Literal = DirectCast(e.Row.FindControl("lCampaignID"), Literal)
lnkCampaign.Text = drview("CampaignTitle").ToString()
lCampaignID.Text = drview("EmailCampaignID").ToString()
lnkCampaign.NavigateUrl = String.Format("/Admin/WF_Admin_Campaign_Email_Detail.aspx?ID={0}", drview("EmailCampaignID").ToString())
End If
End Sub
Protected Sub lnkPageNumberUsage_Click(sender As Object, e As EventArgs)
Dim btn As LinkButton = DirectCast(sender, LinkButton)
grdUsage.PageIndex = btn.CommandArgument
pGrid(sql)
End Sub
I also created an extension for the grid that is also in use.
Public Module ControlUtilities
<Extension()>
Public Sub CustomPager(ByRef grd As GridView)
Dim cp As New clsCustomPager(grd)
End Sub
Public Class clsCustomPager
Public _grd As GridView
Public Property rpt() As GridView
Get
Return _grd
End Get
Set(value As GridView)
_grd = value
End Set
End Property
Public Sub New(ActiveGridView As GridView)
_grd = ActiveGridView
Me.CustomPages()
End Sub
''' <summary>
''' create the objects needed for a bootstrap driven navigation for a gridview
''' </summary>
Sub CustomPages()
If Not _grd Is Nothing And Not _grd.BottomPagerRow Is Nothing Then
'hook event handler to grid
AddHandler _grd.PageIndexChanging, AddressOf Me.Grid_PageIndexChanging
'declare variables
Dim pagerRow As GridViewRow = _grd.BottomPagerRow
Dim lnkPrev As LinkButton = New LinkButton()
Dim lnkNext As LinkButton = New LinkButton()
'set up previous link
lnkPrev.CommandArgument = "Prev"
lnkPrev.CommandName = "Page"
lnkPrev.Text = "<span>«</span>"
'set up next link
lnkNext.CommandArgument = "Next"
lnkNext.CommandName = "Page"
lnkNext.Text = "<span>»</span>"
'create html unordered list
pagerRow.Cells(0).Controls.Add(New LiteralControl("<ul class=""pagination"">"))
'add previous link
pagerRow.Cells(0).Controls.Add(New LiteralControl("<li>"))
pagerRow.Cells(0).Controls.Add(lnkPrev)
pagerRow.Cells(0).Controls.Add(New LiteralControl("</li>"))
Dim pageNumber As Integer
For Each pageNumber In Enumerable.Range(1, _grd.PageCount)
'create page link object
Dim lnkPage As LinkButton = New LinkButton()
lnkPage.CommandName = "Page"
lnkPage.Text = pageNumber
lnkPage.CommandArgument = (pageNumber - 1)
AddHandler lnkPage.Click, AddressOf Me.lnkPageNumber_Click 'event handler
'set css class if selected or not
If (pageNumber - 1) = _grd.PageIndex Then
pagerRow.Cells(0).Controls.Add(New LiteralControl("<li class=""active"">"))
Else
pagerRow.Cells(0).Controls.Add(New LiteralControl("<li>"))
End If
'add lnk and close html listitem
pagerRow.Cells(0).Controls.Add(lnkPage)
pagerRow.Cells(0).Controls.Add(New LiteralControl("</li>"))
Next
'add next link
pagerRow.Cells(0).Controls.Add(New LiteralControl("<li>"))
pagerRow.Cells(0).Controls.Add(lnkNext)
pagerRow.Cells(0).Controls.Add(New LiteralControl("</li>"))
'close up unordered list
pagerRow.Cells(0).Controls.Add(New LiteralControl("</ul>"))
End If
End Sub
''' <summary>
''' event handler for previous/next buttons
''' </summary>
Protected Sub Grid_PageIndexChanging(sender As Object, e As GridViewPageEventArgs)
If e.NewPageIndex >= 0 Then
_grd.PageIndex = e.NewPageIndex
_grd.DataBind()
Me.CustomPages()
End If
End Sub
''' <summary>
''' event handler for numeric link buttons
''' </summary>
Protected Sub lnkPageNumber_Click(sender As Object, e As EventArgs)
Dim btn As LinkButton = DirectCast(sender, LinkButton)
_grd.PageIndex = btn.CommandArgument
_grd.DataBind()
Me.CustomPages()
End Sub
End Class
End Module

Related

Parser Error When Referring Control Value as ASPX Expression

ASPX Code
<asp:RadioButtonList ID="rblApprovalSelection" runat="server"
<asp:ListItem Value="1">Item1</asp:ListItem>
<asp:ListItem Value="2">Item2</asp:ListItem>
<asp:ListItem Value="3" Selected="True">Item3</asp:ListItem>
<asp:ListItem Value="4">Item4</asp:ListItem>
<asp:ListItem Value="5">Item5</asp:ListItem>
</asp:RadioButtonList>
<asp:BoundField DataField="MyData"
Visible='<%#IIf(rblApprovalSelection.SelectedItem.Value=3, False, True) %>'
HeaderText="DataHeader" />
In my above code the below mentioned part is failed and throws error.
Visible='<%#IIf(rblApprovalSelection.SelectedItem.Value=3, False, True) %>'
As suggested by VDWWD the above code should be read as IF instead of IIF().
Error Message
Ok, you don't note/mention how you setting the value of the radio button list.
And since you want to hide/show the value, then I suggest better not to hide the cell, but hide a control in the cell (so it will not mess up grid formatting).
So, say this markup:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table table-hover"
Width="50%" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="Firstname" HeaderText="Firstname" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="City" HeaderText="From City" />
<asp:TemplateField HeaderText="Status">
<ItemTemplate>
<asp:RadioButtonList ID="rblApprovalSelection" runat="server"
AutoPostBack="true"
OnSelectedIndexChanged="rblApprovalSelection_SelectedIndexChanged" >
<asp:ListItem Value="1">Item1</asp:ListItem>
<asp:ListItem Value="2">Item2</asp:ListItem>
<asp:ListItem Value="3" Selected="True">Item3</asp:ListItem>
<asp:ListItem Value="4">Item4</asp:ListItem>
<asp:ListItem Value="5">Item5</asp:ListItem>
</asp:RadioButtonList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText ="Description">
<ItemTemplate>
<asp:Label ID="lblDesc" runat="server"
Text='<%# Eval("Description") %>' ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
So, note how I added a autopost-back for the RB list.
And our code to fill the gv is thus this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid
End If
End Sub
Sub LoadGrid()
Using conn As New SqlConnection(My.Settings.TEST4)
Dim strSQL As String =
"SELECT * FROM tblhotelsA ORDER BY HotelName"
Using cmdSQL As New SqlCommand(strSQL, conn)
conn.Open()
Dim rstData As New DataTable
rstData.Load(cmdSQL.ExecuteReader)
GridView1.DataSource = rstData
GridView1.DataBind()
End Using
End Using
End Sub
But, we need a row data bound event to hide/show that column based on RB seleting.
so, this:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim RB As RadioButtonList = e.Row.FindControl("rblApprovalSelection")
Dim lblDesc As Label = e.Row.FindControl("lblDesc")
lblDesc.Visible = RB.SelectedItem.Value <> 3
End If
End Sub
And the code for the RB change is much the same as the row data binding.
So, this code:
Protected Sub rblApprovalSelection_SelectedIndexChanged(sender As Object, e As EventArgs)
Dim RB As RadioButtonList = sender
Dim gRow As GridViewRow = RB.NamingContainer
Dim lblDesc As Label = gRow.FindControl("lblDesc")
lblDesc.Visible = RB.SelectedItem.Value <> 3
End Sub
And thus we get this result:
So, for a standard GV, I suggest both the RB, and a label templated column, and not use cells (which are for defaulted databound columns). For any non "data bound" column, then you don't use cells, but can/should/will use findcontrol as per above.

Get row id on button click

I need to get a row id from database with the button click.
This is my c# code:
protected void ddlBC_SelectedIndexChanged(object sender, EventArgs e)
{
LogicTableAdapters.getLvLKarTableAdapter getKar = new LogicTableAdapters.getLvLKarTableAdapter();
DataTable dtKar = getKar.getLvLKar(ddlBC.SelectedValue);
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[2]
{
new DataColumn("CharName", typeof(string)),
new DataColumn("LevelID", typeof(int))
});
foreach (DataRow dr in dtKar.Rows)
{
dt.Rows.Add(dr["CharName"].ToString(), dr["LevelID"].ToString());
}
gvKar.DataSource = dt;
gvKar.DataBind();
}
protected void btnButton_Click(object sender, EventArgs e)
{
}
This is dynamically GridView that gets populated by the procedure when item in ddl is selected:
<asp:GridView ID="gvKar" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None" AutoGenerateColumns="False" DataKeyNames="LevelID" OnRowDataBound="gvKarakteristike_RowDataBound">
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:TemplateField HeaderText="Kar">
<ItemTemplate>
<asp:Label ID="Kar" runat="server" Width="150px" Height="30px" Font-Names="Georgia" MyCustomAttr="foo" margin-Left="100px" Text='<%# Bind("CharName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="btnButton" runat="server" Text="Show" autopostback="True"/>
When the button is clicked in form of alert row id from every row must be shown from database.
Can anyone help me please ?
I use code like this to assign a click handler to the row:
Protected Sub Grid_RowDataBound(sender As Object, e As GridViewRowEventArgs)
'apply click attribute to select a row
If e.Row.RowType = DataControlRowType.DataRow Then
e.Row.Attributes("onclick") = ClientScript.GetPostBackClientHyperlink(sender, "Select$" & e.Row.RowIndex)
End If
End Sub
Then this to get the relevant data from the datakeys collection
Protected Sub Grid_RowCommand(sender As Object, e As GridViewCommandEventArgs)
If e.CommandName = "Select" Then
Dim LevelID As String = GridResults.DataKeys(e.CommandArgument).Item("LevelID")
' Do something with ID here
End If
End Sub

how to add different control in gridview row

I have a gridview which I populate from the list data. every row in the gridview has a text box. there is one row within the gridview which I want a dropdown control rather then the textbox. I can't figure out how to change the textbox to dropdown control from a row in the grid.
My gridview below:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" style="width:100%;" ShowHeader="false"
CellPadding="3" BackColor="White" ForeColor="Black" Font-Bold="false" GridLines="None"
RowStyle-CssClass="GridRow">
<Columns>
<asp:TemplateField Visible="false">
<ItemTemplate>
<asp:Label ID="lbl_ItemID" runat="server" Text='<%# Eval("GroupItemTypeID") %>' ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField Visible="false">
<ItemTemplate>
<asp:Label ID="lbl_ItemCode" runat="server" Text='<%# Eval("GroupItemTypeCode") %>' ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ItemStyle-Width="310px" >
<ItemTemplate>
<asp:Label ID="lbl_ItemValuesName" runat="server" Text='<%# Eval("ControlName") %>' ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ItemStyle-Width="245px">
<ItemTemplate>
<asp:TextBox ID="txtPrice" runat="server" CssClass="form-control"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ItemStyle-CssClass="RowWid">
<ItemTemplate>
<asp:Label ID="lbl_IsPercentbased" runat="server" Text='<%# Eval("PercentBasedText") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ItemStyle-Width="70px">
<ItemTemplate>
<asp:CheckBox ID="ChkIsPercent" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code behind
private void GetItemValues()
{
List<Entities.ItemValues> IValues = new List<Entities.ItemValues>();
IValues = BLL.PriceGroupItemValues.GetAllPriceGroupItemValues();
GridView1.DataSource = IValues;
GridView1.DataBind();
}
You can go for this approach in your case :
Put a TextBox and DropDown both in that TemplateField where your TextBox is currently, and set Visible=false in your Dropdown.
Now in your code-behind, you can use the GridView.RowDataBound event to alternatively display the TextBox or the Dropdown whenever and wherever you require. Something like this :
public void CustomersGridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
// set Dropdown visible = true/false as per your requirement.
}
else
{
// set Textboxvisible = true/false as per your requirement.
}
}
This event will fire up for ear row in your GridView and based on the condition that is specified, you can manipulate which control you want to show in that particular row. You can find the dropdown control like this :
foreach (GridViewRow row in GridView1.Rows)
{
categoryName = ((DropDownList)row.FindControl("ddlCategoryName"));
}
Hope this helps.
Use a placeholder control instead of a textbox and programmatically add either a textbox or DDL to the Placeholder control in the rowdatabound event based on your criteria
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="SqlDataSource1"
DataKeyNames="user_id">
<Columns>
<asp:BoundField DataField="user_id" HeaderText="user_id" ReadOnly="True" InsertVisible="False"
SortExpression="user_id"></asp:BoundField>
<asp:BoundField DataField="user_logon" HeaderText="user_logon" SortExpression="user_logon">
</asp:BoundField>
<asp:TemplateField>
<ItemTemplate>
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Sample DataSources
'Primary Datasource to bind to the gridview
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString='<%$ ConnectionStrings:SomeConnectionString %>'
SelectCommand="select top 10 user_id, user_logon from your_user_table"></asp:SqlDataSource>
'Secondary datasource to bind to the ddl
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString='<%$ ConnectionStrings:SomeConnectionString %>'
SelectCommand="select top 5 user_id, user_logon from your_user_table"></asp:SqlDataSource>
Code behind, based on the whether the user_id is odd or even I place one or the other control:
Private Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim ph As PlaceHolder = e.Row.FindControl("PlaceHolder1")
If GridView1.DataKeys(e.Row.RowIndex).Value Mod 2 = 0 Then
Dim tb As New TextBox()
tb.Enabled = False
tb.Text = CType(e.Row.DataItem, DataRowView)("user_logon")
ph.Controls.Add(tb)
Else
Dim ddl As New DropDownList()
ddl.DataSourceID = SqlDataSource2.ID
ddl.DataTextField = "user_logon"
ddl.DataValueField = "user_id"
ph.Controls.Add(ddl)
ddl.DataBind()
End If
End If
End Sub
EDIT based on your Comments:
Private Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim ph As PlaceHolder = e.Row.FindControl("PlaceHolder1")
If CType(e.Row.DataItem, DataRowView)("GroupItemTypeID") ="SUBFREQ" Then
Dim ddl As New DropDownList()
ddl.DataSourceID = <substitute your requirements>
ddl.DataTextField = ...
ddl.DataValueField = ...
ph.Controls.Add(ddl)
ddl.DataBind()
Else
Dim tb As New TextBox()
tb.Enabled = ...whatever...
tb.Text = CType(e.Row.DataItem, DataRowView)("GroupItemTypeID")
ph.Controls.Add(tb)
End If
End If
End Sub
Did some work around with the solution Harvey provided and my existing code. Posting my answer here.
In the gridview, created 2 control and visibility of one control(dropdown) to false
<asp:TemplateField ItemStyle-Width="245px">
<ItemTemplate>
<asp:TextBox ID="txtPrice" runat="server" CssClass="form-control"></asp:TextBox>
<asp:DropDownList ID="ddFrequencyBilling" runat="server" CssClass="form-control" Visible="false"></asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
In the RowDataBound event of the gridview
if (e.Row.RowType == DataControlRowType.DataRow)
{
//foreach( GridViewRow row in GridView1.Rows)
//{
String ItemCode = (e.Row.FindControl("lbl_ItemCode") as Label).Text;
if ( ItemCode == "SUBFREQ")
{
List<Entities.ItemValues> PGItemValues = new List<Entities.ItemValues>();
TextBox TextBoxtemp = ((TextBox)e.Row.FindControl("txtPrice"));
TextBoxtemp.Visible = false;
Label lbel = ((Label)e.Row.FindControl("lbl_IsPercentbased"));
lbel.Visible = false;
CheckBox chk = ((CheckBox)e.Row.FindControl("ChkIsPercent"));
chk.Visible = false;
DropDownList dd1 = ((DropDownList)e.Row.FindControl("ddFrequencyBilling"));
dd1.Visible = true;
PGItemValues = BLL.PriceGroupItemValues.GetItemValueOnCode(ItemCode, 1);
dd1.DataSource = PGItemValues;
dd1.DataTextField = "IValue";
dd1.DataValueField = "ItemCode";
dd1.DataBind();
}
//}
}
and yes it worked. Thanks alot guys.

Making a column editable in an ASP.net GridView

I have a GridView where one of the columns is for a display order for the fields where they will be shown on the front end of my website. Instead of going into each record in the edit page and having to change the order this way, it would be handier to be able to click a button and have the whole DisplayOrder (int) editable, therefore making life alot easier. How can this be done?
Try this code :
<asp:ListBox ID="ListBox1" runat="server">
<asp:ListItem>Manager1</asp:ListItem>
<asp:ListItem>Manager2</asp:ListItem>
<asp:ListItem>Manager3</asp:ListItem>
<asp:ListItem>Manager4</asp:ListItem>
</asp:ListBox>
<asp:GridView ID="UserAllocationGrid" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="Manager" HeaderText="Manager"
SortExpression="managers" />
<asp:TemplateField HeaderText="Allocation Percentage">
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"
Text= '<%# Bind("AllocationPercentage") %>' BorderStyle="None"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code Behind
void fillGV()
{
DataTable UserAllocationTable = new DataTable();
UserAllocationTable.Columns.Add("Manager");
UserAllocationTable.Columns.Add("AllocationPercentage");
// go through listbox1 to find selected managers = selectedManagersList
List<string> selectedManagersListDates = new List<string>();
int counterR = 0;
foreach (ListItem strItem in ListBox1.Items)
{
//selectedManagersListDates.Add(strItem.Value);
DataRow drManagerName = UserAllocationTable.NewRow();
UserAllocationTable.Rows.Add(drManagerName);
UserAllocationTable.Rows[counterR]["Manager"] = strItem.Value;
counterR = counterR + 1;
}
// ViewState["UserAllocationTable"] = UserAllocationTable;
UserAllocationGrid.DataSource = UserAllocationTable;
UserAllocationGrid.DataBind();
}
Use this void in any event I did it in abutton click
protected void Button1_Click(object sender, EventArgs e)
{
fillGV();
}
You can try this using ShowDeleteButton="true" in asp commandfield you can make gridview edidable :-
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowSelectButton="True" />
<asp:BoundField DataField="ID" HeaderText="ID" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
</Columns>
may be help you
You can try below:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" AutoGenerateEditButton = "true">
<Columns>
<asp:BoundField DataField="prodId" HeaderText="Product Id" SortExpression="prodId" ReadOnly = "true" />
<asp:BoundField DataField="prodQuantity" HeaderText="Quantity"
SortExpression="prodQuantity" ReadOnly = "true" />
</Columns>
</asp:GridView>
At Gridview level set AutoGenerateEditButton = "true". This will enable user to edit row.
At Data Field level use ReadOnly = "true" to prevent specific field(in row) from being edited.
Hope this helps.
You can try this, it will give text boxes in column
<asp:Label ID="DescriptionLabel" runat="server"
Text='<%# Eval("Description") %>'></asp:Label>
<asp:TextBox ID="Description" runat="server"
Text='<%# Eval("Description") %>' Width="175px"
visible="false"></asp:TextBox>
</ItemTemplate>
This link had the answer I was looking for. If you have a custom data source, must handle Edit each edit event raised by GridView. In my case:
Protected Sub gMaterias_RowCancelingEdit(sender As Object, e As GridViewCancelEditEventArgs) Handles gMaterias.RowCancelingEdit
gMaterias.EditIndex = -1
BindData()
End Sub
Protected Sub gMaterias_RowEditing(sender As Object, e As GridViewEditEventArgs) Handles gMaterias.RowEditing
gMaterias.EditIndex = e.NewEditIndex
BindData()
End Sub
Protected Sub gMaterias_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) Handles gMaterias.RowUpdating
lError.Visible = False
lError.Text = ""
Dim idMateria As Integer = e.Keys(0)
Dim row As GridViewRow = gMaterias.Rows(e.RowIndex)
Dim tbl As DataTable = Session("Materias")
tbl.Rows(row.DataItemIndex)("universidad") = CType(gMaterias.Rows(e.RowIndex).Cells(5).Controls(0), TextBox).Text
Dim calf = CType(gMaterias.Rows(e.RowIndex).Cells(6).Controls(0), TextBox).Text
If IsNumeric(calf) Then
tbl.Rows(row.DataItemIndex)("calificacion") = calf
Else
lError.Visible = True
lError.Text = "La calificación no es válida"
End If
gMaterias.EditIndex = -1
BindData()
End Sub

GridView Page in UpdatePanel dropping 1 row

I have a basic gridview with paging enabled. I have 11 rows in my database and the gridview's page size is 10. When I come to the page, it shows 10 rows, and in my pager, it shows me on page one with a link to a second page. When I click on the second page, it refreshes the page and goes to page 2 and displays the 11th, lonely row.
When I put an update panel around it, however, it drops the last row. When I come to the page, it shows the same as without the update panel. It shows 10 rows with page 1 and 2 on the pager. When I click on page 2, however, it does it's ajax thing, but doesn't display the last record on the 2nd page. Then, if I go from page 2 back to page 1, it only displays 9 rows instead of the 10 it used to display.
For some reason, when I have an update panel around my gridview, after you page once, it never displays the last row. I have tried all the different combinations of RenderMode, ChildrenAsTriggers and UpdateMode to no avail. I also have a form on the page that allows you to add new rows to the database, and consequently the gridview as well as an edit and delete link inside the gridview, all within the update panel. When I add a new row via the form or edit/delete, this doesn't happen...it only happens when I page.
Any ideas why the gridview won't display the last record/row after I page only when it's inside an update panel?
Here is the code...
ASPX
<asp:UpdatePanel runat="server" ID="uPnl" ChildrenAsTriggers="true" RenderMode="Block" UpdateMode="Always">
<ContentTemplate>
<asp:Panel runat="server" ID="pnlAddComment" CssClass="addComment" DefaultButton="btnSubmitComment">
<h1 class="postComment">Post Comment</h1>
<asp:TextBox runat="server" ID="txtName" CssClass="txtName"></asp:TextBox>
<ajaxToolkit:TextBoxWatermarkExtender ID="txtNameW" runat="server"
TargetControlID="txtName"
WatermarkText="- Type your name here -"
WatermarkCssClass="txtNameWatermark" />
<asp:RequiredFieldValidator runat="server" ID="reqName" ControlToValidate="txtName" Display="Dynamic" ErrorMessage="Please enter your name" ValidationGroup="comment"></asp:RequiredFieldValidator>
<asp:TextBox runat="server" ID="txtComment" TextMode="MultiLine" CssClass="txtComment"></asp:TextBox>
<ajaxToolkit:TextBoxWatermarkExtender ID="TBWE2" runat="server"
TargetControlID="txtComment"
WatermarkText="- Write anything you'd like about this event -"
WatermarkCssClass="txtCommentWatermark" />
<asp:RequiredFieldValidator runat="server" ID="reqComment" ControlToValidate="txtComment" Display="Dynamic" ErrorMessage="Please enter your comment" ValidationGroup="comment"></asp:RequiredFieldValidator>
<div class="buttons">
<asp:Button runat="server" ID="btnSubmitComment" ValidationGroup="comment" Text="Submit Comment" />
<span class="loader">Saving</span>
</asp:Panel>
<h1>Recent Comments</h1>
<a name="comments"> </a>
<asp:GridView runat="server" ID="gvComments" DataKeyNames="CommentID" PagerSettings-Position="TopAndBottom" AllowPaging="true" PageSize="10" AutoGenerateColumns="false" GridLines="None" CssClass="comments">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<div class="comment user">
<p>
<img src="images/icon.gif" width="46" height="55" />
<%#Eval("UserComment")%>
<span>
Posted by <%#Eval("UserName")%> <br/>
on <%#Format(Eval("DateCreated"), "MM/dd/yyyy")%> at <%#Format(Eval("DateCreated"), "h:mm tt")%>
</span>
<asp:LinkButton runat="server" CausesValidation="false" ID="lnkEdit" CssClass="edit" CommandName="Edit" Text="Edit"></asp:LinkButton>
<asp:LinkButton runat="server" ID="lnkDelete" CommandArgument='<%#Eval("CommentID")%>' CssClass="delete" OnClientClick="return confirm('Are you sure you want to delete this comment?');" CausesValidation="false" OnClick="DeleteComment" Text="Delete"></asp:LinkButton>
</p>
</div>
</ItemTemplate>
<EditItemTemplate>
<div class="comment user">
<p>
<img src="images/icon.gif" width="46" height="55" />
<label>Name:</label>
<asp:TextBox runat="server" ID="txtNameEdit" Width="240" Text='<%#Eval("UserName")%>'></asp:TextBox><br />
<label>Comment:</label>
<asp:TextBox runat="server" TextMode="MultiLine" ID="txtCommentEdit" Width="240" Height="100" Text='<%#Eval("UserComment") %>'></asp:TextBox>
<asp:LinkButton runat="server" ID="lnkCancel" CommandName="Cancel" CssClass="cancel" CausesValidation="false" Text="Cancel"></asp:LinkButton>
<asp:LinkButton runat="server" ID="lnkUpdate" CommandName="Update" CssClass="update" CausesValidation="false" Text="Update"></asp:LinkButton>
</p>
</div>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
<PagerStyle CssClass="grdFooter" HorizontalAlign="right" />
<PagerSettings PageButtonCount="7" />
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
VB Code Behind
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
bindComments()
End If
End Sub
Private Sub bindComments()
gvComments.DataSource = dataaccess.getdataset("SELECT * FROM Comments ORDER BY DateCreated DESC", Data.CommandType.Text)
gvComments.DataBind()
End Sub
Protected Sub gvComments_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles gvComments.RowEditing
gvComments.EditIndex = e.NewEditIndex
bindComments()
End Sub
Protected Sub gvComments_RowCancelingEdit(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCancelEditEventArgs) Handles gvComments.RowCancelingEdit
gvComments.EditIndex = -1
bindComments()
End Sub
Protected Sub gvComments_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles gvComments.PageIndexChanging
gvComments.PageIndex = e.NewPageIndex
bindComments()
End Sub
Protected Sub btnSubmitComment_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmitComment.Click
Dim userType As String = "attendee"
If Not IsNothing(Request.QueryString("user")) AndAlso Request.QueryString("user").Length > 0 Then
userType = Request.QueryString("user")
End If
dataaccess.NoReturnQuery("INSERT INTO Comments (UserName, UserComment, UserType) VALUES ('" & txtName.Text.Replace("'", "''") & "','" & txtComment.Text.Replace("'", "''").Replace(vbCrLf, "<br />") & "','" & userType & "')", Data.CommandType.Text)
txtComment.Text = ""
txtName.Text = ""
gvComments.PageIndex = 0
bindComments()
End Sub
Sub DeleteComment(ByVal sender As Object, ByVal e As System.EventArgs)
Dim lnk As LinkButton = TryCast(sender, LinkButton)
If Not IsNothing(lnk) AndAlso IsNumeric(lnk.CommandArgument) Then
dataaccess.NoReturnQuery("DELETE FROM Comments WHERE CommentID = " & lnk.CommandArgument, Data.CommandType.Text)
bindComments()
End If
End Sub
Protected Sub gvComments_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles gvComments.RowUpdating
Dim row As GridViewRow = gvComments.Rows(e.RowIndex)
Dim txtCommentEdit As TextBox = CType(row.FindControl("txtCommentEdit"), TextBox)
Dim txtNameEdit As TextBox = CType(row.FindControl("txtNameEdit"), TextBox)
dataaccess.NoReturnQuery("UPDATE Comments SET UserComment = '" & txtCommentEdit.Text.Replace("'", "''").Replace(vbCrLf, "<br />") & "', UserName = '" & txtNameEdit.Text.Replace("'", "''") & "' WHERE CommentID = " & gvComments.DataKeys(e.RowIndex).Value, Data.CommandType.Text)
gvComments.EditIndex = -1
bindComments()
End Sub
Protected Sub gvComments_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvComments.RowDataBound
Dim lnkDelete As LinkButton = CType(e.Row.FindControl("lnkDelete"), LinkButton)
If Not IsNothing(lnkDelete) Then
If Request.QueryString("user") = "admin" Then
lnkDelete.Visible = True
Else
lnkDelete.Visible = False
End If
End If
Dim lnkEdit As LinkButton = CType(e.Row.FindControl("lnkEdit"), LinkButton)
If Not IsNothing(lnkEdit) Then
If Request.QueryString("user") = "admin" Then
lnkEdit.Visible = True
Else
lnkEdit.Visible = False
End If
End If
End Sub
Try this from the code-behind on Page_Load:
ScriptManager.RegisterAsyncPostBackControl(gvComments);

Categories

Resources