How to get parent GridView's data-bound value - asp.net

<asp:GridView DataSource="Reports">
<ItemTemplate>
<asp:TextBox Text='<%# Bind("ReportId") %>'
<asp:Repeater DataSource="Something that is different than the GridView's DS">
<a href='<%# Bind("ReportId", "reports.aspx?report={0}") %>'/>
</asp:Repeater>
</ItemTemplate>
</asp:GridView>
I know this is inachievable, I am looking for a way to use ReportId from the parent gridview in the nested repeater, is there a way to do it with server side code <%# %>?

Set the gridview
DataKeyField="ReportId"
and in the event GridView1_ItemDataBound inside it
protected void GridView1_ItemDataBound(object sender, GridViewItemEventArgs e)
((TextBox)e.Item.FindControl("TextBox1")).text = GridView1.DataKeys[0].ToString();
and in this case u set the textbox with the value of the ID, try it and hope that it will be usefull.

Related

Passing CommandArguement to LinkButton from variable

I have seen many resources on SO that say that I can use following syntax to pass value to CommandArguement of `LinkButton'
<%forearch(var comment in Comments){%>
<asp:LinkButton ID="del" CommandArguement='<%= comment.CommentId%>' onCommand="delete_click" Text="Delete"/>
<%}%>
But when I write this in my ascx file and click on the link the value passed to command argument is "<%=comment.CommentId%>" instead of commentId itself. Please guide what am I doing wrong?
Edit 1
based on answers and comments, I have moved to use repeater instead of foreach and plain code. Here is the code I have come up with
<asp:Repeater ID="commRepeater" SelectMethod="GetPageComments" runat="server">
<ItemTemplate>
<p>
<%#Eval("Comment") %>
<%if(Page.User.Identity.IsAuthenticated && Page.User.Identity.GetUserId() == Eval("UserId")){ %>
<span>
<asp:LinkButton Text="Edit" runat="server" ID="EditLink" CommandArgument='<%#Eval("CommentId")%>' OnClick="Update_Comment" />
<asp:LinkButton Text="Delete" runat="server" ID="DeleteLink" CommandArgument='<%#Eval("CommentId")%>' OnClientClick="if (!confirm('Are you sure you want delete?')) return false;" OnCommand="Delete_Comment" />
</span>
<%} %>
</p>
</ItemTemplate> </asp:Repeater>
you can see that I am trying to show the edit and delete links if user is logged in and his Id matches with user who commented but it tells me that I can on use Eval in databound controls. how would I hide/show edit/delete links conditionally within repeater
You could simply use codebehind, for example in Page_Load:
protected void Page_Load(Object sender, EventArgs e)
{
if(!IsPostBack)
{
del.CommandArgument = comment.CommentId;
}
}
Maybe a better approach would be to use the Comments-collection(which seems to be a list or array of a custom class) as DataSource of a Repeater(or other web-databound control). Then you can add the LinkButtons to the Itemtemplate.
You can then either use ItemCreated or ItemDataBound events of the repeater in codebehind or inline ASP.NET tags to bind the CommandArgument.
For example:
CommandArguement='<%# DataBinder.Eval( Container.DataItem, "CommentId" ) %>'
What you are doing currently is not recommended and is highly error prone. You can easily achieve this with ASP.NET Repeater control like this:-
<asp:Repeater ID="MyRepeater" runat="server">
<ItemTemplate>
<asp:LinkButton ID="del" CommandArguement='<%# Eval("CommentId") %>'
OnCommand="del_Command" Text="Delete" runat="server" />
</ItemTemplate>
</asp:Repeater>
In Page_Load simply bind it:-
if (!Page.IsPostBack)
{
MyRepeater.DataSource = CommentsRepository();
MyRepeater.DataBind();
}
Or Else if you are have ASP.NET 4.5 then use strongly type Data Bound controls like this:-
<asp:Repeater ID="MyRepeater" runat="server" ItemType="MyNamespace.Comment"
SelectMethod="MyRepeater_GetData">
<ItemTemplate>
<asp:LinkButton ID="del" CommandArguement='<%# Item.CommentId %>'
OnCommand="del_Command" Text="Delete" runat="server" />
</ItemTemplate>
</asp:Repeater>
And you method in code behind should be something like this(just for Demo):-
public IEnumerable<MyNamespace.Comment> MyRepeater_GetData()
{
return new List<Comment>
{
new Comment { CommentId =1, Name= "foo"},
new Comment { CommentId =2, Name= "bar"},
};
}

Why does GridView inside a Repeater (or other similar controls) has the event PageIndexChanging as NOT IMPLEMENTED

Simply I want to know WHY!
Is it the DataSource Type of the GridView? or the Repeater inner implementation?
The error text:
The GridView 'grdArticles' fired event PageIndexChanging which wasn't handled.
Here's the Markup code, I think it's familiar enough for everyone.
<asp:Repeater ID="rptCategories" DataSourceID="ldsCategories" runat="server">
<ItemTemplate>
<asp:GridView runat="server" ID="grdArticles" AllowPaging="true" GridLines="None" DataKeyNames="id" AutoGenerateColumns="false" DataSource='<%# Eval("Articles") %>'>
<Columns>
<asp:TemplateField ShowHeader="false" ItemStyle-Width="100%" FooterStyle-Width="100%">
<ItemTemplate>
<div class="article-menu-item">
<h1>
<asp:HyperLink ID="lnkTitle" CssClass="article-menu-title" runat="server" Text ='<%# Eval("title") %>'
NavigateUrl='<%# Vars.ArticleUrl + "?action=view&id=" + Eval("id") %>' ></asp:HyperLink>
</h1>
<!-- Date -->
<div class="article-menu-date">
<asp:Label ID="Label1" runat="server" Text='<%# Eval("date") %>'></asp:Label>
</div>
<!-- Meta Content -->
<div class="article-menu-meta">
<asp:Label ID="lblContent" runat="server" Text='<%# Bind("meta") %>'></asp:Label>
</div>
<div class="article-menu-delete">
<asp:LinkButton ID="btnDelete" Text="Delete" runat="server" OnClick="btnDelete_Click" TargetID='<%# Eval("id") %>' />
</div>
<!-- Line -->
<div style="border-bottom: 1px solid #ccc"></div>
</div>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<EmptyDataTemplate>
<p>No items to view!</p>
</EmptyDataTemplate>
</asp:GridView>
<br />
</ItemTemplate>
</asp:Repeater>
EDIT:
If I implement the OnPageIndexChanging event using the code (And modified the aspx gridview markup to handle the event):
ASPX:
<asp:GridView runat="server" ID="grdArticles" AllowPaging="true" OnPageIndexChanging="grdArticles_PageIndexChanging" GridLines="None" DataKeyNames="id" AutoGenerateColumns="false" DataSource='<%# Eval("Articles") %>'>
cs:
protected void grdArticles_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView grd = sender as GridView;
grd.PageIndex = e.NewPageIndex;
grd.DataBind();
}
Another exception thrown:
Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.
Edit #2:
After following Mr #Garrison solution, and handling the Repeater itemDataBound event using the code:
protected void rptCategories_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
GridView grd = e.Item.FindControl("grdArticles") as GridView;
if (grd != null)
{
DatabaseDataClassesDataContext dc = new DatabaseDataClassesDataContext();
grd.DataSource = dc.Articles.Where(a => a.category_id == (e.Item.DataItem as Category).id);
grd.DataBind();
}
}
Got another problem: No exceptions thrown, but when navigating to another page, the GridView shows NO ROWS!!
I really think that there is an issue in the repeater core implementation!
You have two options:
Remove Paging: Set AllowPaging="false" in your GridView.
Implement Paging: Set OnPageIndexChanging="grdArticles_PageIndexChanging"
Create a method in your code behind that looks like this:
protected void grdArticles_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
grdArticles.PageIndex = e.NewPageIndex;
grdArticles.DataBind();
}
Now that we're past the first issue, let's tackle the second one. You need to handle your Repeater's ItemDataBound event. Inside there, first find your GridView with the following code:
var grdArticles = (GridView)e.Item.FindControl("grdArticles");
Now you have access to the GridView, but you've got to find the set of Articles you want to data bind to the GridView. I don't know how you're retrieving your data, so I leave that portion up to you, but once you find your list of articles to bind, use the following code:
grdArticles.DataSource = relevantArticles; // relevantArticles is a stand-in variable name, because I don't know how you're going to do it
grdArticles.DataBind();
I've figured out -with the help of others answers- that's the problem is with the DataSource type, which is -in my example- the Eval("Items"), I don't know really what's the type of it, but it's not supporting auto paging.
So, one way to step out of it -without rewriting paging logic and writing lots of code and get some mess with Sessions and querying- is to handle the ItemDataBound of the container of the GridView, I mean the Repeater or DataList, or you can handle the OnPreRender of the GridView and create the DataSource that supports the auto paging like LinqDataSource.
You may also need to handle the PageIndexChanging of the GridView like what #Garrison told us:
protected void grdArticles_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
grdArticles.PageIndex = e.NewPageIndex;
grdArticles.DataBind();
}
After that I got everything work :)

Using hyperlink with querystring for gridview row

Is there someway to turn the row of a gridview into a hyperlink so that when a user opens it in a new tab for example, it goes to that link? Right now I am using a LinkButton and when the user opens it in a new tab, it doesn't know where to go.
I figured the .aspx code would look something like:
<asp:TemplateField>
<ItemTemplate>
<Hyperlink ID="hyperlink" runat="server" ForeColor="red" HtmlEncode="false" navigationURL="testUrl.aspx"
</ItemTemplate>
</asp:TemplateField>
The only thing is, our URLs are set up in the C# code behind as a query string, so I'm not sure how to pass that into the navigationURL section.
I'm guessing there's something I can do on the page_load with the query string to redirect to the page I need, but this is my first time working with query strings so I'm a little confused.
Thanks!
<asp:TemplateField>
<ItemTemplate>
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%#String.Format("~/controller.aspx?routeID1={0}&routeID2={1}", Eval("routeid1"), Eval("routeid2"))%>'></asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
routeid1 and routeid2 are passed as query strings to the controller of that page.
What I did recently is modified my class to have a readonly property that constructs the A tag for me. This way I have control over what gets displayed; just text or a link.
<ItemTemplate>
<asp:Label ID="ColumnItem_Title" runat="server" Text='<%# Bind("DownloadATag") %>'> </asp:Label>
</ItemTemplate>
The code behind just binds an instance of the class to the gridview. You can bind the gridview whenever, on load on postback event, etc.
Dim docs As DocViewList = GetViewList()
GridViewDocuments.DataSource = docs
GridViewDocuments.DataBind()
In the above code, the DocViewList, instantiated as docs, is a list of a class that has all the properties that are needed to fill my GridView, which is named GridViewDocuments here. Once you set the DataSource of your GridView, you can bind any of the source's properties to an item.
Something like:
<asp:LinkButton ID="LinkButton_Title" runat="server" target="_blank"
PostBackUrl='<%# Eval(Request.QueryString["title"]) %>'
or binding them from the RowCreated event:
protected void GridView_OnRowCreated(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
(e.Row.FindControl("LinkButton_Title") as LinkButton).PostBackUrl = Request.QueryString["title"]))
}
}

Lost Focus Events for a Control Within GridView

I have multiple textboxes and dropdown lists within my GridView. For one particular textbox I need trigger a server event which gets data from the database and fills it in other columns of the Grid. Is there a simple way to do it or a slightly complicated way as detailed here
I have no problems implementing the above method or thinking of a work around but then thought that there is Cell Lost Focus in a grid control surprises me a little. Am I missing something ? Any help on this would appreciated.
You can set AutoPostBack to true and handle it's TextChanged event.
<asp:GridView ID="GridView1" runat="server" EmptyDataText="It's Empty.">
<Columns>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:TextBox ID="txtName"
runat="server"
Text='<%#Eval("Name") %>'
AutoPostBack="true"
OnTextChanged="NameChanged" >
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</GridView>
in codebehind:
protected void NameChanged(Object sender, EventArgs e)
{
var txtName = (TextBox) sender;
var row = (GridViewRow) txtName.NamingContainer;
// you could find other controls in this GridViewRow via
// row.FindControl("ControlID") in case of a TemplateField or
// row.Cells[0].Text (0 = index of column) in case of a BoundField
}

Problem with Hyperlink in Repeater Control

<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<li class="closed" >
<asp:HyperLink runat="server" CssClass="toggler off"
ImageUrl="/_layouts/images/NEXT.GIF"
Text="<%#Container.DataItem%>" ID="HyperLink1">
</asp:HyperLink>
</li>
</ItemTemplate>
</asp:Repeater>
I want to get the text in the hyperlink from the arraylist
in my ascx code
I am trying to do this bt its showing error
HyperLink hypl = (HyperLink)Repeater1.FindControl("HyperLink1");
hypl.Text = ar.ToString();
hypl.NavigateUrl = "http//www.yahoo.com";
Anyone is having idea how to resolve this problem
With a repeater control, you can't use FindControl to locate the hyperlink by name because there can be more than one (this is a template, and it gets rendered 0 to n times).
You need to do the assignment of values to the hyperlink multiple times, once for each item that is bound. This is a job for the repeater's ItemDataBound event. Try something like this:
<asp:Repeater ID="Repeater1" runat="server" onitemdatabound="Repeater1_ItemDataBound">
<ItemTemplate>
<li class="closed" >
<asp:HyperLink runat="server" CssClass="toggler off"
ImageUrl="/_layouts/images/NEXT.GIF"
Text="<%#Container.DataItem%>" ID="HyperLink1">
</asp:HyperLink>
</li>
</ItemTemplate>
</asp:Repeater>
Then you need to handle the event like so:
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
HyperLink hypl = (HyperLink)e.Item.FindControl("HyperLink1");
hypl.Text = ar.ToString();
hypl.NavigateUrl = "http//www.yahoo.com";
}

Resources