How to find table cell in asp.net using c# - c#

I want to hide an itemtemplate's data in listview using the td visibility property. Once I click a button it should show the data again that's within the itemtemplate. However, I cannot find the td control using c# in the code behind. Is there a way to find this control or another way to handle this?
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
<asp:Button ID="Button1" runat="server" Text="Search" OnClick="ButtonClick" />
<asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
<asp:View ID="View1" runat="server">
<asp:ListView ID="SectionListView" runat="server" InsertItemPosition="FirstItem" OnPagePropertiesChanged="SectionListView_PagePropertiesChanged">
<ItemTemplate>
<tr style="">
<td></td>
<td id="row1" style="visibility:hidden;" runat="server">
<asp:Label ID="SectionItemLabel" runat="server" Text='<%# Eval("SectionItem") %>' />
</td>
</tr>
</ItemTemplate>
Here is part of the code for the button click:
protected void ButtonClick(object sender, EventArgs e)
{
var temp = (System.Web.UI.HtmlControls.HtmlTableCell)Page.Master.FindControl("MainContent").FindControl("row1");
}

You have a couple of issues. First, when you try to find "row1" within "MainContent", if won't find it because "row1" is actually a child of other children of "MainContent". It won't find them recursively unless you tell them to.
Second, since each ListViewItem within your ListView contains "row1", they are each given their own unique ID, such as SectionListView_ctrl0_row1, SectionListView_ctrl1_row1, etc. Because of this, you need to use FindControl() on each ListViewItem.
But, because you need to do it on each ListViewItem and because each ListViewItem contains "row1", each row will get the same property (i.e. all visible or all invisible). Here is how that could be done:
protected void ButtonClick(object sender, EventArgs e)
{
foreach (ListViewItem lvi in SectionListView.Items)
{
if (lvi.ItemType == ListViewItemType.DataItem)
{
HtmlTableCell row1 = (HtmlTableCell)lvi.FindControl("row1");
row1.Style.Add("visibility", "hidden");
}
}
}
If you need to style each cell individually, they would each need to be named differently. It is common to attach some sort of number or database ID to the end of the ID if that is the case.

Related

ASP.NET Button OnClick within Repeater and LoginView

I'm developing a ASP.NET website with a C# backend. I'm having a problem with how to set an onclick event for buttons that are nested inside of both a loginview and a repeater. The code works fine for displaying all of the other data (anonymous view displays only an error message) but right now the buttons just redirect to the same page and remove the repeater and all contents, whereas they're supposed to run a specific delete function. The repeater, as it is right now, uses an alternatingitem template. If I remove the buttons from the nested controls, they work. I've tried this with buttons, linkbuttons, and imagebuttons. I'd rather use the latter, if possible. Is it possible to assign an Onclick to these buttons if they're nested like this? If not, what approach should I use?
<asp:LoginView ID="LoginLinksView" runat="server" EnableViewState="false">
<AnonymousTemplate>
<asp:Label ID="errorlabel" runat="server"></asp:Label>
</AnonymousTemplate>
<LoggedInTemplate>
<asp:Repeater id="Repeater" runat="server" >
<HeaderTemplate>
<table cellspacing="0" cellpadding="0">
<thead></thead>
</HeaderTemplate>
<ItemTemplate>
<tr class="Repeaterrow">
<!--Additional code here-->
<asp:ImageButton ID="delbutton" runat="server" ImageUrl=
"~/Images/delete.png" Onclick="DeleteOnClick"/>
</tr>
</ItemTemplate>
<AlternatingItemTemplate>
<tr class="Repeaterrow">
<!--Additional code here-->
<asp:ImageButton ID="delbutton" runat="server" ImageUrl=
"~/Images/delete.png" Onclick="DeleteOnClick"/>
</tr>
</AlternatingItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</LoggedInTemplate>
</asp:LoginView>
Here are the problems with your approach
1- The button issues postback as it should. But you need to put some CommandArgument with to identify "key" or which row you are processing it for.
2- Re Bind your Repeater with source. Below is the sample code for you.
protected void Page_Load(object sender, EventArgs e)
{
BindRepeater();
}
private void BindRepeater()
{
List<int> items = new List<int>();
for (int i = 0; i < 10; i++)
{
items.Add(i);
}
Repeater.DataSource = items;
Repeater.DataBind();
}
protected void DeleteOnClick(object sender, EventArgs e)
{
ImageButton delbutton = (sender as ImageButton);
//1- call your method with passing in delbutton.CommandArgument - it will give you key/ whatever you like
//2- Rebind the Repeater here and that will bind controls again...
BindRepeater();
}
protected void Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
ImageButton delbutton = (sender as RepeaterItem).FindControl("delbutton") as ImageButton;
if (delbutton != null)
{
delbutton.CommandArgument = (sender as RepeaterItem).ItemIndex.ToString();
}
}
and ASPX Repeater definition would change to
Thanks,
Riz

How to access a legend tag from code

I have the following data-bound repeater code :
<%--categories--%>
<asp:Repeater ID="CategoryRepeater" runat="server" OnItemDataBound="ItemBound">
<ItemTemplate>
<div class="groupbox">
<fieldset>
<legend><%# Container.DataItem %></legend>
<table>
<asp:Repeater ID="ItemRepeater" runat="server">
<ItemTemplate>
<tr>
<td>
<asp:CheckBox id="chkItem" runat="server" Text='<%# Eval("Text")%>' />
<asp:HiddenField id="pgNos" runat="server" Value='<%# Eval("PGNos")%>' />
<asp:Button ID="btnXRefs" Text="x-refs" runat="server" CssClass="xRefButton" OnClick="btnSelectXRefs_Click" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
</fieldset>
</div>
</ItemTemplate>
</asp:Repeater>
There is a repeater inside a repeater. How do I access the text inside the legend (<legend><%# Container.DataItem %></legend>) from code?
I tried :
foreach (RepeaterItem cr in CategoryRepeater.Items)
{
string heading = (string) cr.DataItem; // returns null
}
Container.DataItem is a runtime alias for the DataItem for this specific item in the bound list. For a Repeater which displays 10 rows of data, this is one row from the datasource...Basically, it's a specific row and at runtime you can get the Property Values from this row
I saw your above Mark Up...Seems like you are missing to mention the property of Data-Bound type Class like below.
<%# ((Your Class Name)Container.DataItem).Class Property Name %>
There is a repeater inside a repeater. How do I access the text inside
the legend (<%# Container.DataItem %>) from code?
As told by phemt.latd, you can change the Legend tag into server side control like below.
<legend id="lg" runat="server">
<%# ((Your Class Name)Container.DataItem).Class Property Name %>
</legend>
Now, in the Item-Bound Data Event, Find the Legend Control.
protected void rpt_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
HtmlGenericControl ctl = (HtmlGenericControl)e.Item.FindControl("lg");
ctl.InnerText //This is what will give you the result.
}
}
The legend tag that you use is not visible on server side. Is a client control and not a server one.
Try with this:
<legend id="myLegend" runat="server"><%# Container.DataItem %></legend>
Then in codebehind:
protected void ItemBound(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.DataItem == null) return;
HtmlGenerics body = (HtmlGenerics)e.Item.FindControl("myLegend");
body.InnerText = "Foo";
}

Placing ListView DataItem Property into UserControl Template

Sort of new to .NET and trying to understand how best to accomplish this task: I have a listview with a datasource containing a list of string values. The last property is some text that I'd like to place in the Text template; normally when not used inside a listview I can place markup and text inside the template successfully, so I'd like to keep this structure. But what would be a way of placing that string inside there? I've tried Databinder.Eval but as expected it says that the template doesn't contain the property I'm referring to from Container.DataItem (which becomes the template).
<asp:ListView runat="server"
ID="ListView1"
OnItemDataBound="ListView1_ItemDataBound">
<LayoutTemplate>
<div class="navigation">
<asp:PlaceHolder runat="server" id="itemPlaceholder" />
</div>
</LayoutTemplate>
<ItemTemplate>
<my:Control id="VideoLink1" runat="server">
<Text>
--- PLACE CONTENT HERE --
</Text>
</my:Control>
</ItemTemplate>
</asp:ListView>
Anyone have an idea how to accomplish this? Would be greatly appreciated.
Use ItemDatabound event of the ListView. In that find your control and then assign the desired properties.
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
YourControl VideoLink1= e.Item.FindControl("VideoLink1") as YourControl ;
if(VideoLink1!= null)
{
YourClass obj = ((YourClass)(((System.Web.UI.WebControls.ListViewDataItem)(e.Item)).DataItem));
VideoLink1.TextProperty = obj .TextProperty ;
}
}
}

Once clicking the select button of a row, a gridview appears between that row and the rest of the gridview. Possible?

I'd like to have the user click the select button of, lets say, the 250th row of a 400 row gridview. When they click that, then another gridview that's 3x12 appears below that row, then the 150 other rows appear below that. Is this at all possible? I guess I could create a whole other div that'll have three gridviews that output depending on being <= and > the index of the selected row.
It starts as:
Gridview rows 1-400
Then after row 350 is selected is it:
Gridview rows 1-350
Gridview of row 350 info
Gridview rows 351-400.
It's definitely possible, but I would use a ListView or DataList as your parent container instead, because with a GridView, you'll have to put the child list in a column, which will look ugly. This should put you on the right path:
<asp:ListView ID="lstOuterList" runat="server" DataKeyNames="ID, OtherColumn">
<LayoutTemplate>
<table width="100%">
<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><asp:LinkButton ID="LinkButton1" runat="server" Text="Expand" OnCommand="LinkButton1_Command" CommandArgument='<%#Container.DisplayItemIndex%>'></asp:LinkButton></td>
<td><%#Eval("Value")%></td>
<td><%#Eval("OtherValue")%></td>
<td><%#Eval("OtherOtherValue")%></td>
</tr>
<asp:PlaceHolder ID="plcInnerList" runat="server">
<asp:ListView ID="lstInnerList" runat="server" Width="100%">
<LayoutTemplate>
<tr>
<td colspan="4">
<div style="padding:20px;background-color:#fffeee;">
<table width="100%">
<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
</table>
</div>
</td>
</tr>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><%#Eval("Value")%></td>
<td><%#Eval("OtherValue")%></td>
<td><%#Eval("OtherOtherValue")%></td>
</tr>
</ItemTemplate>
</asp:ListView>
</asp:PlaceHolder>
</ItemTemplate>
</asp:ListView>
And when the user clicks the LinkButton/Button in DataList1, do something like this:
protected void LinkButton1_Command(object sender, CommandEventArgs e)
{
//pass index of item in command argument
var itemIndex = Convert.ToInt32(e.CommandArgument);
//find the pnlChildView control
var innerPlaceHolder = lstOuterList.Items[itemIndex].FindControl("plcInnerList") as PlaceHolder;
if (innerPlaceHolder != null)
{
innerPlaceHolder.Visible = !innerPlaceHolder.Visible;
if (innerPlaceholder.Visible)
{
var innerList = innerPlaceHolder.FindControl("lstInnerList") as ListView;
if (innerList != null)
{
//the id to retrieve data for the inner list
int keyValue = (int)lstOuterList.DataKeys[itemIndex]["ID"];
//bind the list using DataList1 data key value
innerList.DataSource = new DataTable("DataSource"); //your datasource
innerList.DataBind();
}
}
}
}
one way is:
on the rowcommand of the main grid:
create c# code for the grid will be inside GridView grd = new GridView();
bind this instance like any other grid
add on the controls from the main grid current line, should be something like
e.Cells[0].Controls.Add(grd);
I don't have VS here right now but I guess you could get the idea, I use this approach all the time

How to pass in runtime a index of row for ListView?

I have an question, On my page i have a ListView control, I also have a button that has CommandArgument. I know i can read and find a control in the ListView as :
ListView.Items[i].FindControl("controlname");
and my button in ListView is like that
asp:Button ID="WisdomButton" runat="server" CommandName="UpdateWisdom" CommandArgument='<%# need my index for Item[i] to post here %>'
OnCommand="UpdateWisdom" Text="Update" />
I want to add index value in runtime to the CommantParameter, so when i go to the Function onCommand i will know exactly from what row[i] i Need to get my controls from ListView.
So my question is, how do i dinamicly add index of ListView.Rows[i] into CommmandArgument for the Button in runtime ?
Thanks in advance.
Check out the API
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listviewcommandeventargs.aspx
The ListViewCommandEventArgs item has an index, IE it is already available in the argument
ListViewDataItem dataItem = (ListViewDataItem)e.Item;
int i = dataItem.DisplayIndex;
But from here you will have access to those controls
e.Item.FindConrol("controlName");
If you are calling the method a different way you could aways assign the index through an ItemDataBound Event
void MyListView_ItemDataBound(object sender, ListViewItemEventArgs e)
{
((Button)e.Item.FindControl("WisdomButton")).CommandArgument = ((ListViewDataItem)e.Item).DisplayIndex;
}
OR try something like this for giggles
<asp:Button runat="server" CommandArgument='<%# DisplayIndex %>'/>
// OR
<asp:Button runat="server" CommandArgument='<%# NextIndex() %>'/>
It might help to know a little bit more about what your are trying to do. If your end goal is to get any of the properties from your bound object you can just cast the dataItem from the ListViewCommandEventArgs of the ItemCommand event. You don't need to retain the index or call FindControl at all.
Here is an example of how to get the bound Customer object.
ListView
<asp:ListView runat="server" id="Customers" ItemCommand="Customers_ItemCommand">
<LayoutTemplate>
<ul>
<asp:placeholder runat="server" id="itemPlaceholder" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<asp:Button runat="server" id="Select" CommandName="Select" />
<%# Eval("Name")%>
</li>
</ItemTemplate>
</asp:ListView>
CodeBehind
public void Page_Load()
{
if (!Page.IsPostBack)
{
this.Customers.DataSource = GetCustomers();
this.Customers.DataBind();
}
}
public void Customers_ItemCommand(object sender, ListViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
if (e.Item.ItemType != ListViewItemType.DataItem)
return;
var customer = ((ListViewDataItem)e.Item).DataItem as Customer;
if (customer != null)
{
// Now work directly with the customer object.
Response.Redirect("viewCustomer.aspx?id=" + customer.Id);
}
}
}
Edit: In addtion when you cast the item to a ListViewDataItem, then you also expose a ((ListViewDataItem)e.Item).DataItemIndex property that might help you.

Categories