ASP.NET MultiView with multiple repeaters - asp.net

I have a problem and I need your opinion. I have a control with a MultiView and each view will be a different render for the control's output, it will be about 10 different views. Inside each view I will have a repeater that will repeat a few rows, this repeater will be the same for all views and since the MultiView only allows 1 view to be show at any one time, I though to have the repeater with the same ID, so I don't have to make 10 bindings and create 10 OnItemDataBound events with the exact same code in it, but ASP.NET don't let me have the repeater with the same ID (it should be smarter than that for this case). I am using C# and v4 of the framework.
Here's the MultiView code:
<asp:MultiView id="MultiView" runat="server">
<asp:View id="h400" runat="server">
<div class="latest_Wide">
<h3>Wide</h3>
<asp:Repeater id="rptLatest" runat="server" OnItemDataBound="rptLatest_OnItemDataBound">
<ItemTemplate>
<p>• <asp:Literal id="litPostTitle1" runat="server" /></p>
</ItemTemplate>
</asp:Repeater>
</div>
</asp:View>
<asp:View id="h200" runat="server">
<div class="latest_Narrow">
<h3>Narrow</h3>
<asp:Repeater id="rptLatest" runat="server" OnItemDataBound="rptLatest_OnItemDataBound">
<ItemTemplate>
<p>• <asp:Literal id="litPostTitle2" runat="server" /></p>
</ItemTemplate>
</asp:Repeater>
</div>
</asp:View>
...
</asp:MultiView>
How can I solve this problem. Remember I don't want to make 10 repeater bindings and have 10 OnItemDataBound events with the exact same code, for the case you suggest to give the repeaters different IDs.

This isn't pretty... but:
Assume your ASCX:
<asp:MultiView id="mvPostDisplay" runat="server">
<asp:View id="h400" runat="server">
<div class="latest_Wide">
<h3>Wide</h3>
<asp:Repeater runat="server" OnItemDataBound="rptLatest_OnItemDataBound">
<ItemTemplate>
<p>• <asp:Literal id="litPostTitle1" runat="server" /></p>
</ItemTemplate>
</asp:Repeater>
</div>
</asp:View>
<asp:View id="h200" runat="server">
<div class="latest_Narrow">
<h3>Narrow</h3>
<asp:Repeater runat="server" OnItemDataBound="rptLatest_OnItemDataBound">
<ItemTemplate>
<p>• <asp:Literal id="litPostTitle2" runat="server" /></p>
</ItemTemplate>
</asp:Repeater>
</div>
</asp:View>
...
</asp:MultiView>
In your codebehind:
private void DataBindRepeater()
{
View activeView = this.mvPostDisplay.GetActiveView();
Repeater myRepeater = this.FindRepeater(activeView);
if (myRepeater != null)
{
myRepeater.DataSource = this.GetDataSourceFormSomewhere();
myRepeater.DataBind();
}
}
private Repeater FindRepeater(Control container)
{
if (container is Repeater)
{
return container as Repeater;
}
else
{
foreach (Control c in container.Controls)
{
Repeater retVal = this.FindRepeater(c);
if (retVal != null)
{
return retVal;
}
}
return null;
}
}
And simply call DataBindRepeater after you've determined the appropriate view. Please note rptLatest will not be set, therefor you will need to get a reference to your repeater in your handler using either the sender, FindRepeater, or possibly something less hackish.

Have you considered making the repeater a user control? This way you have all the repeater binding code once in your user control. Each view will have it's own instance of the usercontrol.
Is this a direction you are willing to take?

Related

Binding ListView Field to Value in Code-Behind

I'm displaying fields from a DB call in a ListView. I had to re-code my database query because of an issue with repeating groups. I also didn't want to have to deal with nested ListViews. So now I am trying to set the header to the value of radio button list selection. I was trying to write a custom method to return that value but could not remember the syntax.
How can I set the header in the LayoutTemplate from the code-behind so that it doesn't repeat?
<LayoutTemplate>
<div class="resultsGrid">
<strong><%# GetHeader() %></strong>
<asp:PlaceHolder runat="server" ID="resultsPlaceHolder">
</asp:PlaceHolder>
</div>
</LayoutTemplate>
<ItemTemplate>
// rest of data
</ItemTemplate>
I was able to solve this as follows:
<asp:ListView ID="resultsList" ItemPlaceholderID="resultsPlaceHolder"
OnItemCreated="ResultsList_ItemCreated" runat="server">
<LayoutTemplate>
<div class="resultsGrid">
<strong><asp:Label ID="headerLabel" runat="server"></asp:Label></strong>
<asp:PlaceHolder runat="server" ID="resultsPlaceHolder">
</asp:PlaceHolder>
</div>
</LayoutTemplate>
<ItemTemplate>
// rest of data
</ItemTemplate>
</asp:ListView>
And in the code-behind:
protected void ResultsList_ItemCreated(object sender, ListViewItemEventArgs e)
{
if (e.Item is ListViewItem)
{
Label tempLabel = resultsList.FindControl("headerLabel") as Label;
tempLabel.Text = ViewState["ParkName"].ToString();
}
}

Reaching repeater item: The Logic

Here is my design page:
<asp:MultiView ID="mvProducts" runat="server" ActiveViewIndex="0">
<asp:View runat="server" ID="mvProducts1">
<asp:Repeater ID="rptDiscount" runat="server">
<ItemTemplate>
<div class="divProduct1">
<div class="divProductHeader">
<asp:Panel ID="pnlDiscount" runat="server" CssClass="divProductHeaderDiscount" Visible="true">
<div class="menuTextTopSpacer"></div>
<asp:Label ID="lblDiscount" runat="server" Text='<%#Eval("discount") %>'></asp:Label>
</asp:Panel>`
I just want to reach pnlDiscount item but I dont know how. I made a search but it just helped to increase my confusion.
Indeed, I want to learn the logic on finding a control in a repeater.
Use ItemDataBound on your reapter then use FindContol() to get to the Panel
protected void rptDiscount_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Panel myPanel= e.Item.FindControl("pnlDiscount") as Panel;
//Do some work
}

ListView.DataItem is showing null

Listview binding code
<asp:Content ID="Content3" ContentPlaceHolderID="leftColumnPlaceHolder" runat="server">
<asp:ListView ID="lvQuestions" runat="server" OnItemDataBound='lvQuestions_ItemDataBound'>
<LayoutTemplate>
<div id="itemPlaceholder" runat="server">
</div>
<asp:Button ID="btnSubmitAnswers" runat="server" Text="Submit Answers" OnClick="btnSubmitAnswers_Click" />
</LayoutTemplate>
<ItemTemplate>
<div>
<%# Container.DataItemIndex + 1 %>:<%# Eval("Body") %>
</div>
<asp:RadioButtonList ID="rdlAnswers" runat="server" DataSource='<%#Eval("ExamAnswer") %>' DataTextField='Body' DataValueField="AnswerId">
</asp:RadioButtonList>
</ItemTemplate>
</asp:ListView>
</asp:Content>
While fetching the listview items on submit button click..like below,
we are getting qsnItem.DataItem as NULL.
foreach (ListViewDataItem qsnItem in lvQuestions.Items)
{
}
Please suggest what is going wrong here.
The DataItem of all databound web-controls in ASP.NET are null on postbacks when you don't DataBind the control again, which is unnecessary when ViewState is enabled(default).
So you can use the controls in your templates to get the values:
foreach (ListViewDataItem qsnItem in lvQuestions.Items)
{
RadioButtonList rdlAnswers = (RadioButtonList)qsnItem.FindControl("rdlAnswers");
}
If you need to old values you need to load them from database or use the ListViewUpdatedEventArgs.OldValues Property.

Insert a User Control within an ASP:Repeater

I need to insert a user control into a repeater
<asp:Repeater runat="server" ID="rptAdditionalPages">
<ItemTemplate>
<div id="<%# ((ftj.com.AdditionalPageForProductDetail)Container.DataItem).DivID %>" class="tab_content">
<h1><%# ((ftj.com.AdditionalPageForProductDetail)Container.DataItem).Title %></h1>
<%# ((ftj.com.AdditionalPageForProductDetail)Container.DataItem).Body %>
<uc:EnrollmentMethod ID="EnrollmentMethod2" runat="server" />
</div>
</ItemTemplate>
</asp:Repeater>
When the user control is inserted with this method the code behind cannot find EnrollmentMethod2. Is it possible to add user controls in repeaters?
You can't find it because it's nested in the repeater. You will need to dig into the repeater to find it.
foreach (RepeaterItem item in Repeater1.Items)
{
EnrollmentMethod control = (EnrollmentMethod )item.FindControl("EnrollmentMethod2");
}

ASP.NET TreeView, select NodeTemplate upon databinding similar to the TemplateSelector in WPF?

Usage scenario,
I have hierarchically categorized items and I would like to present them in a TreeView. The TreeView will be populated on demand and it contains both the categories and the items, I would like to have different templates for the categories and the items. That is not a problem if the items were static I could easily list them in the aspx markup and specify template for each node, but on demand populating I have no clue how to do it. I don't mind any solution suggesting usage of Telerik TreeView or DevExpress Treeview.
Thanks in advanced.
Ok,
one day and no comment :), I got it done using RadTreeView, the RadTreeNode supports custom attributes, I added a custom attribute to distinguish between a category and an item, and in the NodeTemplate I used MultiView control which chooses the View to display by checking the node custom attribute.
Here is some parts of the code,
<telerik:RadTreeView ID="rtvQueries" runat="server" OnNodeExpand="rtvQueries_NodeExpand"
Skin="Black" OnClientNodeClicking="CheckNodeType" OnNodeClick="rtvQueries_NodeClick">
<NodeTemplate>
<asp:HiddenField ID="hfId" runat="server" Value='<%# Container.Value %>' />
<asp:MultiView ID="mvAll" runat="server" ActiveViewIndex='<%# Container.Attributes["ItemType"] == "C"? 0 : 1 %>'>
<asp:View ID="vwCategory" runat="server">
<asp:Label ID="lblCategory" runat="server" Text='<%# Container.Text %>' />
</asp:View>
<asp:View ID="vwQuery" runat="server">
<div style="float: left">
<asp:Label ID="lblQuery" runat="server" Text='<%# Container.Text %>' />
</div>
<div style="float: left; margin-left: 20px; overflow: hidden; width: 200px;">
<asp:Label ID="lblCommandText" runat="server" Text='<%# Container.Attributes["CommandText"] %>' />
</div>
</asp:View>
</asp:MultiView>
</NodeTemplate>
</telerik:RadTreeView>
The code-behind for NodeExpand,
protected void rtvQueries_NodeExpand(object sender, RadTreeNodeEventArgs e)
{
Guid categoryId = new Guid(e.Node.Value);
List<Category> cats = DBHelper.GetQueryCategories(categoryId);
cats.ForEach(c =>
{
RadTreeNode n = new RadTreeNode(c.Name, c.Id.ToString());
n.ExpandMode = TreeNodeExpandMode.ServerSideCallBack;
n.Attributes["ItemType"] = "C";
e.Node.Nodes.Add(n);
n.DataBind();
});
List<RightBI.Query> queries = DBHelper.GetQueriesByCategoryId(categoryId);
queries.ForEach(q =>
{
RadTreeNode n = new RadTreeNode(q.Name, q.Id.ToString());
n.Attributes["ItemType"] = "Q";
n.Attributes["CommandText"] = q.CommandText;
e.Node.Nodes.Add(n);
n.DataBind();
});
}
The only problem in this solution is I have to call DataBind on each node after adding it to the TreeView so the binding expressions evaluated.
I still would like to see other solutions and comments on this solution or better ideas.

Resources