Switching a Repeater's ItemTemplate at runtime - asp.net

Is it possible to define multiple templates for a Repeater's ItemTemplate and switch between them according to some condition?
I use a repeater to view a list of posts but want to have a different view for rows that belong to the current user (e.g. contains a LinkButton for deleting the post)
If this is not possible, then is it possible to use a Multiview control inside a Repeater's ItemTemplate?

I tried to use a MultiView control inside the ItemTemplate and it worked very well, hope this helps someone with the same problem:
<asp:Repeater ID="Repeater1" runat="server" OnItemCommand="Repeater1_ItemCommand">
<ItemTemplate>
<asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="<%# ((Post)Container.DataItem).Member.ID == CurrentMemberID ? 1 : 0 %>">
<asp:View ID="View1" runat="server"><!-- some links --></asp:View>
<asp:View ID="View2" runat="server"><asp:LinkButton CommandName="DeletePost" CommandArgument="<%# ((Post)Container.DataItem).Id %>" ID="LinkButton1" runat="server">Delete Post</asp:LinkButton></asp:View>
</asp:MultiView>
</ItemTemplate>
</asp:Repeater>

I don't know if it's possible to switch between templates, but I've found the the Repeater.OnItemDataBound event most useful for modifying the display of individual repeater items.
For example, to show a link button based on the current user...
protected void repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
LinkButton = e.Item.FindControl("btnDelete");
LinkButton.Visible = (e.Item.DataItem as DataRow)["CreatedBy"] == getCurrentUser();
}
Generally I keep the layout of the data consistent for each repeater item and modify the visual appearance by altering the CssStyle and Visible properties of controls in the template. If there are more radical layout changes, I'll put each layout option inside a placeholder and use logic to determine which placeholder to show.

Related

Reacting to Button commands inside a Web Usercontrol in a ASP.NET Repeater

I have an ASP.NET repeater, whose ItemTemplate is a WebUsercontrol named ProviderControl.
<asp:Repeater ID="rep" runat="server" OnItemDataBound="rep_ItemDataBound">
<ItemTemplate>
<custom:ProviderControl ID="row" runat="server" />
</ItemTemplate>
</asp:Repeater>
I am populating the custom control with data in the ItemDataBound event.
Inside the provider control I have two buttons that I want to be able to react to on the containing Page.
I know there are Commands, and Command arguments, but how would I do that?
Or is there an easier way than using Commands?
You have to handle ItemCommand event of "Repeater".
protected void Repeater1_ItemCommand(object source, RepeaterCommandEventArgs e)
{
Button btn = e.CommandSource as Button;
Response.Write(btn.ID);
}
The best way would be to provide custom events in your UserControl for each button-click event. The UserControl will raise and the page can handle them.
http://www.codeproject.com/Articles/8797/Mastering-Page-UserControl-Communication#4.3

Link button in Repeater control redirect to grid view

I am developing a web application where I have a repeater control. A link button is inside the repeater control. When the link button is clicked, I want it to redirect to a page which would be a data entry page for that particular user(which was clicked). It has to use the user-id/emplid and pre-populate some fields in the new page and other fields should be allowed for data-entry.
My question-
How should I redirect to the new data entry page? I haven't decided on the page yet. I am thinking that it would be a form page or grid view and would be a separate page.
Code:
<asp:LinkButton ID="getDetails" OnCommand="getDetails_cmd" runat="server"
CommandArgument='<%#DataBinder.Eval(Container.DataItem,"Emplid")%>
' Text='<%#DataBinder.Eval(Container.DataItem,"NAME")%>'
CommandName="Details"></asp:LinkButton>
After redirecting to the page, I guess, using the commandargument, I can get the emplid. an I pass multiple values? Say the keys for the page?
How should I update multiple tables in the page?
Any help would be really appreciated.
Thanks,
You need handle ItemCommand event of Repeater control.
<asp:Repeater ID="Repeater1" runat="server"
onitemcommand="Repeater1_ItemCommand">
<ItemTemplate>
<asp:LinkButton
ID="getDetails"
runat="server"
Text='<%# Eval("NAME") %>'
CommandName="cmd"
CommandArgument='<%# Eval("Empid") %>'
>
</asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
Handler of ItemCommand event,
protected void Repeater1_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "cmd")
{
Session["empid"]=e.CommandArgument;
Response.Redirect("~/page1.aspx");
}
}
If you're trying to direct to a new page, linkbutton is probably not the way to go since it does a postback to the same form normally, a standard hyperlink sending emplid in the querystring would work. In the new page get the emplid from the querystring using Request.Querystring("emplid"). As for saving to multiple tables, there are a number of ways to do that, one would be to wrap the multiple db update calls in a transactionscope.

Dynamically adding a Button to a PlaceHolder in a DataGrid

I have basically something like this:
<asp:datagrid id="DGrid" runat="server" AutoGenerateColumns="false">
<asp:TemplateColumn HeaderText="Stuff">
<ItemTemplate>
<asp:PlaceHolder id="PH" runat="server" />
</ItemTemplate>
</asp:TemplateColumn>
</asp:datagrid>
I need to add a Button to the PlaceHolder depending on the values of the data I am binding. At the moment I am adding the Button after the data is bound in Page_Load. The problem is that the data binding methods are not called in postbacks, so the Button disappears when I click on it.
Any suggestions on how to do this? Problem is that I need to know some attributes of the grid item to create the Button, so I cannot create it before the data has been bound.
How about subscribing to ItemCreated event?
Markup:
<asp:datagrid id="DGrid" runat="server" OnItemCreated="DGrid_ItemCreated" AutoGenerateColumns="false">...</asp:DataGrid>
Code-behind:
protected void DGrid_ItemCreated(object sender, DataGridItemEventArgs e)
{
var ph e.Item.FindControl("PH") as PlaceHolder;
// ...
}
UPDATE
Regarding the situation when the e.Item.DataItem is null on a postback: only the reliable information (e.g. databound control properties) is persisted across postbacks (if ViewState is enabled), the entire data items don't survive them. Therefore you have to manage the state by yourself. You can persist only the necessary data in a ViewState (and not the entire data items since it can blow it up).

ASP.NET : Access controls declared in TemplateColumn of DataGrid

ASCX File:
<asp:datagrid runat="server" id="gridFormFields" datakeyfield="FieldID"
autogeneratecolumns="False"
onitemcommand="gridFormFields_ItemCommand" onitemdatabound="gridFormFields_ItemDataBound">
<columns>
<asp:templatecolumn>
<itemtemplate>
<asp:imagebutton runat="server" id="buttonMoveUpFormField" resourcekey="buttonMoveUpFormField"
commandname="Item" commandargument="MoveUp" imageurl="~/images/up.gif" />
</itemtemplate>
</asp:templatecolumn>
<asp:templatecolumn>
<itemtemplate>
<asp:imagebutton runat="server" id="buttonMoveDownFormField" resourcekey="buttonMoveDownFormField"
commandname="Item" commandargument="MoveDown" imageurl="~/images/dn.gif" />
</itemtemplate>
</asp:templatecolumn>
</columns>
Code behind:
protected void gridFormFields_ItemDataBound(object sender, DataGridItemEventArgs e)
{
(e.Item.FindControl("buttonMoveUpFormField") as ImageButton)
.Visible = gridFormFields.Items.Count > 1 && e.Item.ItemIndex > 0;
(e.Item.FindControl("buttonMoveDownFormField") as ImageButton)
.Visible = gridFormFields.Items.Count > 1 && e.Item.ItemIndex < gridFormFields.Items.Count - 1;
}
In the code behind, the Control returned by FindControl is null. Why?
How can I access the buttonMoveUpFormField and buttonMoveDownFormField controls?
From the code behind, is it possible to access controls which are declared in the ItemTemplate section of the TemplateColumn section of a DataGrid?
Because you need to add code to include "Item" and "AlternatingItem" and exclude all other types, before you try to find that control.
if (e.Item.Type == ...
You can certainly access the controls that are within the ItemTemplate section. I'm dealing with a similar issue. One thing that I've found is, depending what is calling your "gridFormFields_ItemDataBound", you may not have access to those controls yet.
I know that in my instance, I've got an "ItemTemplate" and an "EditItemTemplate", when I click edit, it fires an event "RowEditing" before it is actually switched to "Edit Mode", so the control will not be there yet. I do though have access to the controls in "RowUpdating" which is fired when I click save in the edit mode.
Maybe this helps? For example, your "OnDataBound" might be the event that is trying to access your controls, but you may not have access to them on databound?
Just a thought. I'll edit this if I get any further on mine.

Setting a asp repeater data source

I have a asp.net repeater control in a aspx page, with runat="server" and an id set, however for some reason i can't access its ID from code behind (I can access the id of the asp:detaislview control it sits in though). So instead in the page_load method I am doing the following:
Repeater repeater = (Repeater)PromotionSitesDetailsView.FindControl("estateRepeater");
repeater.DataSource = estateList;
However when run, an error comes up saying the repeater is null! All I want to do is set the datasource of this repeater to a List object. Any ideas?
You said the Repeater sits inside a DataList. The DataList is, itself, a kind of repeater - the controls inside of it don't exist until the DataList is bound to a datasource, and the controls in the template are created once per item in the source. So if you bind the DataList to a source with 3 items, you will get 3 repeaters.
So it looks kind of like this:
Page
MyDataList
Item0
MyRepeater
Item1
MyRepeater
Item2
MyRepeater
So obviously MyDataList.FindControl("MyRepeater") can't work - which "MyRepeater" are we talking about? Since multiple controls cannot have the same ID, ASP.NET solves this by making the ID unique to something called a NamingContainer. Since the DataList repeats the same set of controls many times (once per item in the data source), each item in the DataList is a NamingContainer.
We need to find the NamingContainer we know holds the instance of MyRepeater that we want:
MyDataList.Items[0].FindControl("MyRepeater");
You can iterate over the items in the DataList after it has been bound (of course, before it has been bound it has no items). You can also operate on a given item in the DataList as that item is being created:
<asp:DataList OnItemDataBound="MyDataList_HandleItemDataBound" ... />
//this will get called once per item as it is created
void MyDataList_HandleItemDataBound(object sender, DataListItemEventArgs e)
{
//e.Item is the current item being databound
Repeater myRepeater = e.Item.FindControl("MyRepeater") as Repeater;
myRepeater.DataSource = //ds
myRepeater.DataBind();
}
You can do it without code-behind, simply by assigning the Repeater DataSource. Here is an example of a two level hierarchical menu:
<ul>
<asp:Repeater ID="ctlMenu" runat="server">
<ItemTemplate>
<li>
<asp:HyperLink runat="server"
NavigateUrl='<%#(Container.DataItem as MyPage).GetUrl()%>'
Text="<%# (Container.DataItem as MyPage).GetName() %>"></asp:HyperLink>
<ul>
<asp:Repeater runat="server" DataSource="<%# (Container.DataItem as MyPage).GetChildren() %>">
<ItemTemplate>
<li>
<asp:HyperLink runat="server"
NavigateUrl='<%#(Container.DataItem as MyPage).GetUrl()%>'
Text="<%# (Container.DataItem as MyPage).GetName() %>"></asp:HyperLink>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</ItemTemplate>
</asp:Repeater>
</ul>

Resources