Nested Class In ASP Repeater - c#

I have a nested class that contains order items for an order:
public class Order
{
public int ItemID { get; set; }
public int CustomerId { get; set; }
...
public List<OrderItem> Items { get; set; }
}
public class OrderItem
{
public int ItemId { get; set; }
...
}
and I have this databound to an asp repeater
var result = [method to get data]
rptOrders.DataSource = result;
rptOrders.DataBind();
and in the ascx page I have
<asp:Repeater ID="rptOrders" runat="server" HideControlForZeroRows="true" ZeroRowsText="You have no orders.">
<HeaderTemplate>
<table>
<tr class="tableHeader">
<td>Order #</td>
...
</tr>
</HeaderTemplate>
<ItemTemplate>
<ItemTemplate>
<tr>
<td><a href='#'><%# Eval("ItemID") %></a></td>
...
</tr>
</ItemTemplate>
but I want to use an accordion to show hide the order details, an example is here: http://jsfiddle.net/Xqk3m/, which means I have to add rows to my repeater table for the nested class items.
How do I reference the nested class to have another repeater iterate over the elements to add a for each of the nested items?
I have looked around the web and generally they are suggesting that I have a nested repeater call the nested class separately but really I want to make use of the fact that I have well defined classes. Hopefully I can do something like:
//parent repeater
<asp:Repeater ID="rptOrders" runat="server" HideControlForZeroRows="true" ZeroRowsText="You have no orders.">
....
//nested repeater
<asp:Repeater ID="rptOrderItems" runat="server" HideControlForZeroRows="true">
but how can I reference the order items for the order?
<asp:Repeater runat="server" DataSource="<%# Container.DataItem %>">
<ItemTemplate>
<tr>
<td><%# Eval("ItemId") %></td>
</tr>
</ItemTemplate>
</asp:Repeater>

You can add ItemDataBound event to rptOrders repeater:
protected void rptOrders_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var order = (Order)e.Item.DataItem;
Repeater innerRep = e.Item.FindControl("rptOrderItems") as Repeater;
innerRep.DataSource = order.Items;
innerRep.DataBind();
}
In fact you can have any other data-bound control inside repeater item and bind it using list from DataItem.

Related

Atata – How to check hidden checkbox within table?

I am using Atata Framework and working on the following scenario—There's a table with checkbox within TD element. I want to be able to invoke Click() method on the checkbox, but couldn't get it work correctly.
The truncated HTML is as following:
<table data-v-c4547572="" class="invGrid">
<tr data-v-c4547572="" row-id="3ed5bcf4-473d-43ae-991a-ffe36d5e0a53" class="row-index-0">
<td data-v-c4547572="" class="column-index-0 checkbox-col">
<input data-v-c4547572="" type="checkbox" element-id="3ed5bcf4-473d-43ae-991a-ffe36d5e0a53" class="">
<label data-v-c4547572="" for="3ed5bcf4-473d-43ae-991a-ffe36d5e0a53"></label>
</td>
<td data-v-c4547572="" class="column-index-1">
<span data-v-c4547572="" class="val-name">Some text</span>
<span data-v-c4547572="" class="arrow pull-right dsc"></span>
</td>
</tr>
</tbody>
</table>
The code I'm using is:
// The page class:
[FindByCss(".invGrid")]
public Table<GroupsRow, Page> Inventory { get; set; }
// The row class:
public class GroupsRow : TableRow<Page>
{
[FindByIndex(0)]
public CheckBox<Page> CheckBox { get; set; }
[FindByCss(".val-name")]
public Text<Page> Text { get; set; }
}
As an additional note, invoking Exists() on the checkbox yields false:
inv.CheckBox.Exists(); // false
Any idea how to make the checkbox to be operational?
I can guess that your check box is actually hidden, and <label> is used as a wrapper for custom rendering. As almost all controls in Atata are looking for visible elements by default, you can specify Visibility:
[FindByIndex(0, Visibility = Visibility.Any)]
public CheckBox<Page> CheckBox { get; private set; }
It should find the check box. But if click on it will not work (as it can be hidden), you can add a property for label and click it:
[FindFirst]
public Label<Page> CheckBoxLabel { get; private set; }

Pass and loop Strongly Types Data List to WebForm

I am coming from MVC background where I can pass the model data list from controller to view more in structure manner. I need to now how I can pass storgly typed model data from C# class to page.
I am using ASP.NET 3.5
Model Class
public class RolesModel
{
public RolesModel() { }
public long RoleID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime CreatedDate { get; set; }
}
I have managed to bring list data in aspx.cs class... how I can loop form data in aspx page???
Roles.aspx.cs class
protected void Page_Load(object sender, EventArgs e)
{
List<RolesModel> roleList = new List<RolesModel>();
roleList = RoleDefinationRelay.GetAllRoles(null);
}
aspx
<table>
<thead>
<tr>
<td>Role ID</td>
<td>Title</td>
<td>Description</td>
<td>Created Date</td>
</tr>
</thead>
<tbody>
<tr>
<%foreach(var item in %>???????????
</tr>
</tbody>
</table>
Following is using ASP:Repeater control. Hope this helps
in your .aspx
<form runat="server">
<asp:Repeater id="rptRoles" runat="server">
<HeaderTemplate>
<table border="1" width="100%">
<tr>
<td>Role ID</td>
<td>Title</td>
<td>Description</td>
<td>Created Date</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%#Eval("RoleID")%></td>
<td><%#Eval("Title")%></td>
<td><%#Eval("Description")%></td>
<td><%#Eval("CreatedDate")%></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</form>
.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack){
List<RolesModel> roleList = new List<RolesModel>();
roleList = RoleDefinationRelay.GetAllRoles(null);
//set data source of repeater and bind
rptRoles.DataSource = roleList;
rptRoles.DataBind();
}
}
The issue is that you are thinking about it from an MVC point of view - I had the same issue in reverse because my background in webforms!
in webforms you dont bind your data that way (you can - but it takes more work and its not really the accepted way)
What you need is in your aspx is a server control that will handle the looping and rendering for you - for this example im going to use a gridview because its quick, but if you need more control over your HTML you should use a repeater or a listview.
Your code behind is almost there...
protected void Page_Load(object sender, EventArgs e)
{
List<RolesModel> roleList = new List<RolesModel>();
roleList = RoleDefinationRelay.GetAllRoles(null);
//Bind the gridview
gvRoles.DataSource = roleList;
gvRoles.DataBind();
}
then in your aspx page:
< asp:GridView id="gvRoles" runat="server" />
What is happening here is in the page_load you are getting the data, assigning it to a servercontrol (Setting the datasource) and telling the control to render it (Databind)
When the page is processed your code will fire, getting your list of roles which will be passed over to the gridview which knows that its got to generate a table with a row for each item in your list and a column for each property for each of the items...
As I said above if you need more control over the HTML that it outputs have a look at a repeater and the ListView controls.
Hope that helps!

NullReferenceException when defining a custom object in ASPX

I'm trying to create a custom Context Menu as a user control. The code behind for this user control looks like this:
public partial class UCContextMenu : UserControl
{
private List<ContextMenuItem> m_menuItems = new List<ContextMenuItem>();
protected void Page_Load(object sender, EventArgs e)
{
}
[PersistenceMode(PersistenceMode.InnerProperty)]
public List<ContextMenuItem> Items
{
get { return m_menuItems; }
set { m_menuItems = value; }
}
public event EventHandler Command;
}
Then, I defined the ContextMenuItem type in the same namespace as the user control (in the same file actually) which is essentially a menu item:
public class ContextMenuItem
{
public string Name { get; set; }
public string Text { get; set; }
}
The ascx page for the user control includes a repeater control which is defined like this:
<div id="contentHolder">
<ul id="ulContextMenu" style="display: none; z-index: 1000; border-width: 0.8px;
font-size: 13px;" class="ui-corner-all">
<asp:Repeater runat="server" DataSource="<%# Items %>">
<ItemTemplate>
<li><a href='#<%# DataBinder.Eval(Container.DataItem, "Name") %>'>
<%# DataBinder.Eval(Container.DataItem, "Text") %></a>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</div>
And finally to use it in a page after registering it, I have:
<uc:ContextMenu runat="server" OnCommand="SomeMethod">
<Items>
<uc:ContextMenuItem Name="SomeName" Text="SomeText" />
</Items>
</uc:ContextMenu>
Now when I run this, I get a NullReference parse error on line
<uc:ContextMenuItem Name="SomeName" Text="SomeText" />
When not running, Visual Studio also says Element 'ContextMenuItem' is not a known element. It doesn't catch the exception at runtime either so maybe that way I could look at the stack trace to see what's going on. I was just wondering if anyone has encountered similar issues like this. Any help is appreciated.
Create ContextMenuItem as a normal user control. The fact that you are defining it in the same namespace as you have emphasized doesn't help you in any way.
So, just add ContextMenuItem.ascx to your project and then register and add the control on page or other control.

ASP.NET Custom control with content templates

I creating the "clone" of LoginView ASP.NET control in ASP.NET 3.5, for our company needs and I'm trying to understand how it achieved the ability to set controls with same ID in different templates.
For example this is ASPX markup with LoginView control:
<asp:LoginView ID="lv" runat="server">
<AnonymousTemplate>
<asp:Label ID="lbl" runat="server" />
</AnonymousTemplate>
<LoggedInTemplate>
<asp:Label ID="lbl" runat="server" />
</LoggedInTemplate>
</asp:LoginView>
This is valid markup and page works fine.
Now I created my custom control:
[ParseChildren(true)]
[PersistChildren(false)]
public class ContentControl : Panel
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public PlaceHolder AnonymousView { get; set; }
[PersistenceMode(PersistenceMode.InnerProperty)]
public PlaceHolder LoggedinView { get; set; }
public ContentControl()
{
this.Init += new EventHandler(ContentControl_Init);
}
void ContentControl_Init(object sender, EventArgs e)
{
if (AnonymousView == null)
{
AnonymousView = new PlaceHolder();
}
if (LoggedinView == null)
{
LoggedinView = new PlaceHolder();
}
this.Controls.Add(AnonymousView);
this.Controls.Add(LoggedinView);
AnonymousView.ID = "AnonymousView";
LoggedinView.ID = "LoggedinView";
AnonymousView.Visible = !MyContext.IsLogged;
LoggedinView.Visible = MyContext.IsLogged;
}
}
Now when I use my control with following markup, I receive the error that control with ID "lbl" exists more than once on page:
<TL:ContentControl ID="c" runat="server" CssClass="dd">
<AnonymousView>
AnonymousView
<asp:Label ID="lbl" runat="server" />
</AnonymousView>
<LoggedinView>
LoggedinView
<asp:Label ID="lbl" runat="server" />
</LoggedinView>
</TL:ContentControl>
How I can allow to have controls with same ID in both templates?
You need to develop templated control: Building Templated Custom ASP.NET Server Controls
And use control that implement INamingContainer as template container: Use TemplateInstance.Single to avoid FindControls

Temporary Datasource

I have a gridview bound to a sql server datasource. I am currently moving selected items to a ListBox to show chosen records. I'd like to switch to the ReOrderList from the AJAX Toolkit to be able to reorder the selected items. Unfortunately, the ReorderList needs a true datasource to bind to. What is the best practice for creating some sort of temporary table that the user would use?
OK, what you could do is persist your temporary list datasource in viewstate. Here's a rough example:
<asp:ScriptManager ID="SM1" runat="server"></asp:ScriptManager>
<ajaxToolkit:ReorderList ID="RList" runat="server"
DragHandleAlignment="Left" ItemInsertLocation="End"
AllowReorder="true" ShowInsertItem="true" PostBackOnReorder="false">
<ItemTemplate>
<p><%# Eval("ID") %> = <%# Eval("Name") %></p>
</ItemTemplate>
</ajaxToolkit:ReorderList>
<asp:Button ID="ButtonAdd" runat="server" OnClick="ButtonClick_AddItem" Text="Add New" />
Then in codebehind:
public partial class SortList : System.Web.UI.Page
{
[Serializable]
public class MyItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public MyItem(Guid id, string name)
{
Id = id;
Name = name;
}
}
protected List<MyItem> MyList
{
get
{
if (ViewState["myClass"] == null)
ViewState["myClass"] = new List<MyItem>();
return (List<MyItem>)ViewState["myClass"];
}
}
protected void AddItem(Guid id, string name)
{
MyList.Add(new MyItem(id, name));
RList.DataSource = MyList;
RList.DataBind();
}
protected void ButtonClick_AddItem(object sender, EventArgs e)
{
AddItem(Guid.NewGuid(), DateTime.Now.Ticks.ToString());
}
}
Obviously you would substitute MyItem class with whatever you want to store and replace the button with the GridView select item event. But hopefully the principle is there?
I don't follow. The ReOrderList has a DataSourceID property to which you can just point at your existing SqlDataSource. Or do you not actually have an SqlDataSource control?
If not, how are you binding the data to your GridView? If you are binding to some kind of object colllection then you could use an ObjectDataSource instead, so long as it implements IList interface. Perhaps have a read of ReorderList - bind to DataTable if you are trying to bind to a DataTable instead.

Categories

Resources