I am new to asp.net (web forms) and want to get some information from database and then display this information in the form of posts , like heading , paragraph and an image. If there are three rows in database there would be three posts. I have done this using asp.net code in .aspx file
<%
while (reader.Read())
{ %>
<article class="col1">
<h2><%= reader.GetValue(0).ToString()%></h2>
<p class="pad_bot1"><%= reader.GetValue(1).ToString()%></p>
<img src="<%= reader.GetValue(2).ToString() %>" class="img" alt="">
</article>
<% } reader.Close(); %>
But I read somewhere that the code must be separated and it should be written in .aspx.cs file. What's the way to do this ? Assigning id's to the h and p tags and then assigning them values like this :
while (reader.Read())
{
h.InnerText = reader.GetValue(0).ToString();
p.InnerText = reader.GetValue(1).ToString();
}
But this does not solve the problem , because the posts will not be displayed in a loop i.e. 3 times.
I want to know a most suitable solution , thanks in advance
This is my code you can modify as you wish
Code behind
// Here's your object that you'll create a list of
private class Products
{
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public string ProductPrice { get; set; }
}
// Here you pass in the List of Products
private void BindItemsInCart(List<Products> ListOfSelectedProducts)
{
// The the LIST as the DataSource
this.rptItemsInCart.DataSource = ListOfSelectedProducts;
// Then bind the repeater
// The public properties become the columns of your repeater
this.rptItemsInCart.DataBind();
}
Aspx code
<asp:Repeater ID="rptItemsInCart" runat="server">
<HeaderTemplate>
<table>
<thead>
<tr>
<th>Product Name</th>
<th>Product Description</th>
<th>Product Price</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("ProductName") %></td>
<td><%# Eval("ProductDescription")%></td>
<td><%# Eval("ProductPrice")%></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody>
</table>
</FooterTemplate>
</asp:Repeater>
Using web forms, that would be easiest to solve using a Repeater control.
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.repeater.aspx
Related
(This is intended as a Q/A style question, intended to be a go-to resource for people that ask similar questions. A lot of people seem to stumble on the best way of doing this because they don't know all the options. Many of the answers will be ASP.NET specific, but AJAX and other techniques do have equivalents in other frameworks, such as socket.io and SignalR.)
I have a table of data that I have implemented in ASP.NET. I want to display changes to this underlying data on the page in real time or near real time. How do I go about it?
My Model:
public class BoardGame
{
public int Id { get; set;}
public string Name { get; set;}
public string Description { get; set;}
public int Quantity { get; set;}
public double Price { get; set;}
public BoardGame() { }
public BoardGame(int id, string name, string description, int quantity, double price)
{
Id=id;
Name=name;
Description=description;
Quantity=quantity;
Price=price;
}
}
In lieu of an actual database for this example, I'm just going to store the data in the Application variable. I'm going to seed it in my Application_Start function of my Global.asax.cs.
var SeedData = new List<BoardGame>(){
new BoardGame(1, "Monopoly","Make your opponents go bankrupt!", 76, 15),
new BoardGame(2, "Life", "Win at the game of life.", 55, 13),
new BoardGame(3, "Candyland", "Make it through gumdrop forrest.", 97, 11)
};
Application["BoardGameDatabase"] = SeedData;
If I were using Web Forms, I'd display the data with a repeater.
<h1>Board Games</h1>
<asp:Repeater runat="server" ID="BoardGameRepeater" ItemType="RealTimeDemo.Models.BoardGame">
<HeaderTemplate>
<table border="1">
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%#: Item.Id %></td>
<td><%#: Item.Name %></td>
<td><%#: Item.Description %></td>
<td><%#: Item.Quantity %></td>
<td><%#: Item.Price %></td>
</tr>
</ItemTemplate>
<FooterTemplate></table></FooterTemplate>
</asp:Repeater>
And load that data in the code behind:
protected void Page_Load(object sender, EventArgs e)
{
BoardGameRepeater.DataSource = Application["BoardGameDatabase"];
BoardGameRepeater.DataBind();
}
If this were MVC using Razor, it's just a simple foreach over the model:
#model IEnumerable<RealTimeDemo.Models.BoardGame>
<h1>Board Games</h1>
<table border="1">
<tr>
<th>
#Html.DisplayNameFor(model => model.Id)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Description)
</th>
<th>
#Html.DisplayNameFor(model => model.Quantity)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
</tr>
}
</table>
Let's use Web Forms to have a little page for adding data so we can then watch the data update in real time. I recommend you create two browser windows so you can see the form and table at the same time.
<h1>Create</h1>
<asp:Label runat="server" ID="Status_Lbl" /><br />
Id: <asp:TextBox runat="server" ID="Id_Tb" /><br />
Name: <asp:TextBox runat="server" ID="Name_Tb" /><br />
Description: <asp:TextBox runat="server" ID="Description_Tb" /><br />
Quantity: <asp:TextBox runat="server" ID="Quantity_Tb" /><br />
Price: <asp:TextBox runat="server" ID="Price_Tb" /><br />
<asp:Button runat="server" ID="SubmitBtn" OnClick="SubmitBtn_Click" Text="Submit" />
And the code behind:
protected void SubmitBtn_Click(object sender, EventArgs e)
{
var game = new BoardGame();
game.Id = Int32.Parse(Id_Tb.Text);
game.Name = Name_Tb.Text;
game.Description = Description_Tb.Text;
game.Quantity = Int32.Parse(Quantity_Tb.Text);
game.Price = Int32.Parse(Price_Tb.Text);
var db = (List<BoardGame>)Application["BoardGameDatabase"];
db.Add(game);
Application["BoardGameDatabase"] = db;
//only for SignalR
/*var context = GlobalHost.ConnectionManager.GetHubContext<GameHub>();
context.Clients.All.addGame(game); */
}
SignalR
This is the answer I'm most excited to share, because it represents a much cleaner implementation that is lightweight and works well in today's mobile (data constricted) environment.
There have been several methods over the years to provide "realtime" pushing of data from the server to the client (or the appearance of pushing data). Rapid Short Polling (similar to my AJAX based answers), Long Polling, Forever Frame, Server Sent Events, and WebSockets are different transport mechanisms used to achieve this. SignalR is an abstraction layer capable of selecting an appropriate transport mechanism based on the client and server's capabilities. The best part of using SignalR is that it's simple. You don't have to worry about the transport mechanism, and the programming model is easy to understand.
I'm going to define a SignalR hub, but just leave it empty.
public class GameHub : Hub
{
}
When I add data to the "database", I'm going to run the below bit of code. If you read the question, you'll see I commented it out in the "create" form. You'll want to uncomment that.
var context = GlobalHost.ConnectionManager.GetHubContext<GameHub>();
context.Clients.All.addGame(game);
Here's my page code:
<h1>SignalR</h1>
<asp:Repeater runat="server" ID="BoardGameRepeater" ItemType="RealTimeDemo.Models.BoardGame">
<HeaderTemplate>
<table border="1">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody id="BoardGameTblBody">
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%#: Item.Id %></td>
<td><%#: Item.Name %></td>
<td><%#: Item.Description %></td>
<td><%#: Item.Quantity %></td>
<td><%#: Item.Price %></td>
</tr>
</ItemTemplate>
<FooterTemplate></tbody></table></FooterTemplate>
</asp:Repeater>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="Scripts/jQuery-1.6.4.min.js"></script>
<script src="Scripts/jquery.signalR-2.1.1.min.js"></script>
<script src="signalr/hubs"></script>
<script type="text/javascript">
var hub = $.connection.gameHub;
hub.client.addGame = function (game) {
$("#BoardGameTblBody").append("<tr><td>" + game.Id + "</td><td>" + game.Name + "</td><td>" + game.Description + "</td><td>" + game.Quantity + "</td><td>" + game.Price + "</td></tr>");
};
$.connection.hub.start();
</script>
And the code behind:
protected void Page_Load(object sender, EventArgs e)
{
BoardGameRepeater.DataSource = Application["BoardGameDatabase"];
BoardGameRepeater.DataBind();
}
Notice what's happening here. When the server calls context.Clients.All.addGame(game); it's executing the function that's been assigned to hub.client.addGame for every client that is connected to the GameHub. SignalR is taking care of wiring up the events for me, and automatically converting my game object on the server to the game object on the client. And best of all, there's no network traffic back and forth every few seconds, so it's incredibly lightweight.
Advantages:
Very light on the network traffic
Easy to develop, but still flexible
Doesn't send viewstate with the request
Doesn't poll the server continuously.
Note, you could add a function on the client for editedGame for pushing changed data out to the client easily (same for delete).
Timer/UpdatePanel
If you are using Web Forms, you can use a control called an UpdatePanel. The UpdatePanel is capable of refreshing sections of the page asynchronously, without causing a postback of the entire page. Combined with an asp:Timer, you can have the table update as often as you like. Here's the code:
<asp:ScriptManager runat="server" />
<h1>Board Games (using Update Panel)</h1>
<asp:Timer runat="server" ID="UP_Timer" Interval="5000" />
<asp:UpdatePanel runat="server" ID="Game_UpdatePanel">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="UP_Timer" EventName="Tick" />
</Triggers>
<ContentTemplate>
<asp:Repeater runat="server" ID="BoardGameRepeater" ItemType="RealTimeDemo.Models.BoardGame">
<HeaderTemplate>
<table border="1">
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%#: Item.Id %></td>
<td><%#: Item.Name %></td>
<td><%#: Item.Description %></td>
<td><%#: Item.Quantity %></td>
<td><%#: Item.Price %></td>
</tr>
</ItemTemplate>
<FooterTemplate></table></FooterTemplate>
</asp:Repeater>
</ContentTemplate>
</asp:UpdatePanel>
And the code behind:
protected void Page_Load(object sender, EventArgs e)
{
BoardGameRepeater.DataSource = Application["BoardGameDatabase"];
BoardGameRepeater.DataBind();
}
So let's talk about how this one works. Every 5 seconds, the timer is going to fire a Tick event. This is registered as an asynchronous postback server with the UpdatePanel, so a partial postback occurs, the entire page lifecycle runs again, so it reloads the data on the Page Load event, then the entire contents of of the UpdatePanel's content template is replaced with freshly generated data from the server. Let's look at how the network traffic might look:
+5s Client => Server | Run the page lifecycle, send me the contents of the ContentPanel.
Server => Client | Here's the entire contents of the ContentPanel.
+10s Client => Server | Run the page lifecycle, send me the contents of the ContentPanel.
Server => Client | Here's the entire contents of the ContentPanel.
+15s Client => Server | Run the page lifecycle, send me the contents of the ContentPanel.
Server => Client | Here's the entire contents of the ContentPanel.
Advantages:
Simple to implement. Just add a timer, a script manager, and wrap the repeater in an update panel.
Disadvantages:
Heavy: The ViewState is sent to the server with every request. The impact of this can be lightened if you disable ViewState however (which you should do anyways).
Heavy: Whether the data has changed or not, you're sending all of the data over the line every 5 seconds. That's a huge chunk of bandwidth.
Slow: Takes a long time with each partial postback since all the data goes across the wire.
Tough to work with: When you begin adding more functionality, it can be tricky to correctly handle the partial postbacks properly.
Not smart: Even if the previous request didn't finish, it'll continue posting back thanks to the timer.
Not smart: No easy way to handle network interruption.
AJAX Polling, better implementation
Similar to the other AJAX based answer, you can continually poll the server. But this time, instead of responding with the data to display, we're going to reply with a list of ID's of the data. The client side is going to keep track of the data it's already retrieved in an array then it will make a separate GET request to the server for data when it sees a new ID has been added.
Here's our page code:
<h1>Board Games (AJAX Polling Good)</h1>
<table id="BoardGameTbl" border="1">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody id="BoardGameTblBody">
</tbody>
</table>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
var loadedGames = [];
function getListOfGames() {
$.ajax({
type: "GET",
url: "api/GamesApi/GetGameIds",
dataType: "json"
})
.done(function (data) {
for (i = 0; i < data.length; i++) {
if (loadedGames.indexOf(data[i]) == -1) {
loadedGames[loadedGames.length] = data[i];
getGame(data[i]);
}
}
setTimeout(getListOfGames, 5000);
});
}
function getGame(id) {
$.ajax({
type: "GET",
url: "api/GamesApi/GetGame/" + id,
dataType: "json"
})
.done(function (game) {
$("#BoardGameTblBody").append("<tr><td>" + game.Id + "</td><td>" + game.Name + "</td><td>" + game.Description + "</td><td>" + game.Quantity + "</td><td>" + game.Price + "</td></tr>");
});
}
getListOfGames();
</script>
Here's the Web API Controller:
namespace RealTimeDemo.Controllers
{
public class GamesApiController : ApiController
{
[Route("api/GamesApi/GetGameIds")]
public IEnumerable<int> GetGameIds()
{
var data = HttpContext.Current.Application["BoardGameDatabase"] as List<BoardGame>;
var IDs = data.Select(x => x.Id);
return IDs;
}
[Route("api/GamesApi/GetGame/{id}")]
public BoardGame GetGame(int id)
{
var data = HttpContext.Current.Application["BoardGameDatabase"] as List<BoardGame>;
return data.Where(x => x.Id == id).SingleOrDefault();
}
}
Now, this is a much better implementation than my other AJAX based answer and the Timer/UpdatePanel answer. Since we're only sending the ID's across every 5 seconds, it's a much lighter strain on network resources. It'd also be fairly trivial to handle no network connection situations, or to execute some sort of notification when new data has been loaded, such as throwing up a noty.
Advantages
Doesn't send viewstate with request.
Doesn't execute entire page lifecycle
Only ID's are sent across the wire (could be improved if you sent a timestamp with the request, and only replied with data that's changed since the timestamp) as part of the polling. Only new objects are retrieved from the database.
Disadvantages
- We're still polling, generating a request every few seconds. If the data doesn't change very often, you're needlessly using up bandwidth.
AJAX Polling, poor implementation
If you are using MVC or Web Forms, you can implement a technique called AJAX polling. This will constantly send an AJAX request to the server. The server will send a response containing the latest data. It is incredibly simple to implement. You don't have to use jQuery to use AJAX, but it makes it a lot easier. This example is going to use Web API for the server side functionality. Web API is similar to MVC, it uses routing and controllers to process requests. It's the replacement for ASMX Web Services.
This is the web forms code, but it's very similar to the MVC code so I'm going to omit that:
<h1>Board Games (AJAX Polling Bad)</h1>
<table id="BoardGameTbl" border="1">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody id="BoardGameTblBody">
</tbody>
</table>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
function getData() {
$.ajax({
type: "GET",
url: "api/GamesApi/GetGameData",
dataType: "json"
})
.done(function (data) {
$("#BoardGameTblBody").empty();
for (i = 0; i < data.length; i++) {
$("#BoardGameTblBody").append("<tr><td>" + data[i].Id + "</td><td>" + data[i].Name + "</td><td>" + data[i].Description + "</td><td>" + data[i].Quantity + "</td><td>" + data[i].Price + "</td></tr>");
}
setTimeout(getData, 5000);
});
}
getData();
</script>
This is making a request to a Web API. The API is returning a JSON representation of all the games.
public class GamesApiController : ApiController
{
[Route("api/GamesApi/GetGameData")]
public IEnumerable<BoardGame> GetGameData()
{
var data = HttpContext.Current.Application["BoardGameDatabase"] as List<BoardGame>;
return data;
}
}
The overall result of this method is similar to the Timer/UpdatePanel method. But it doesn't send any viewstate data with the request, and it doesn't execute a long page lifecycle process. You also don't have to dance around detecting if you're in a postback or not, or if you're in a partial postback or not. So I consider this an improvement over Timer/UpdatePanel.
However, this method still has one of the major disadvantages of the Timer/UpdatePanel method. You're still sending all of the data over the wire with each AJAX request. If you look at my other AJAX based answer, you'll see a better way to implement AJAX polling.
Advantages
Doesn't send viewstate with request.
Doesn't execute entire page lifecycle
Disadvantages
Generates a request every few seconds
Response includes all data, even if it hasn't changed
I wanted to use a GridView for binding a picture list. I can already do this, but I need to control how wide the grid goes.
If it was a table it would be easy like this:
<table>
<tr>
<td>Image 1</td>
<td>Image 2</td>
<td>Image 3</td>
</tr>
<tr>
<td>Image 4</td>
<td>Image 5</td>
<td>Image 6</td>
</tr>
<tr>
<td>Image 7</td>
<td>Image 8</td>
<td>Image 9</td>
</tr>
</table>
I want the "gridview" to not have any real columns or anything, just simply pictures with a text descriptor below them from my database. Is the repeater control better for this?
I would use a DataList control. The DataList control has very useful properties called RepeatColumns, and RepeatLayout which allow you to do what you need.
Markup:
<asp:DataList ID="DataList1" runat="server" RepeatColumns="3">
<ItemTemplate>
<img src="<%#Eval("url") %>" />
</ItemTemplate>
</asp:DataList>
Sample Class:
public class Sample
{
public string url { get; set; }
}
Binding DataList:
protected void Page_Load(object sender, EventArgs e)
{
List<Sample> samples = new List<Sample>();
samples.Add(new Sample() { url = "http://www.google.com/images/srpr/logo4w.png" });
samples.Add(new Sample() { url = "http://www.google.com/images/srpr/logo4w.png" });
samples.Add(new Sample() { url = "http://www.google.com/images/srpr/logo4w.png" });
samples.Add(new Sample() { url = "http://www.google.com/images/srpr/logo4w.png" });
samples.Add(new Sample() { url = "http://www.google.com/images/srpr/logo4w.png" });
samples.Add(new Sample() { url = "http://www.google.com/images/srpr/logo4w.png" });
this.DataList1.DataSource = samples;
this.DataList1.DataBind();
}
Result: A HTML table with 2 rows with 3 columns each showing the google image.
<table id="Table1" cellspacing="0" style="border-collapse: collapse;">
<tr>
<td>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</td>
<td>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</td>
<td>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</td>
</tr>
<tr>
<td>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</td>
<td>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</td>
<td>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</td>
</tr>
</table>
From my understanding of your question, you want to out put the images in a form other than a table.
A DataList controls has built-in features that would make your life easier. Namely, RepeatColumns, and RepeatLayout. #Hanlet's answer explains this very well. The problem with his answer, from my understanding of your question, is that he only shows how to output as a table. Which, as I explained earlier is not what you are looking for. The DataList can display the output in a different way: RepeatLayout="Flow". The potential problem with this approach is that the layout is rigid. It will not allow you to change how it is displayed. It uses <span> and <br /> tags to display the data. While this can be styled using CSS, it is still somewhat limiting. Here is how the output from Hanlet's answer would look if you choose Flow instead of Table :
<div>
<span id="DataList1">
<span>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</span>
<span>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</span>
<span>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</span>
<br />
<span>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</span>
<span>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</span>
<span>
<img src="http://www.google.com/images/srpr/logo4w.png" />
</span>
</span>
</div>
All that being said, if you want the unlimited control over the layout that a Repeater provides, there is a way to do this. Using two Repeaters:
aspx code:
<asp:Repeater ID="rptRows" runat="server" OnItemDataBound="rptRows_ItemDataBound">
<ItemTemplate>
<asp:Repeater ID="rptItems" runat="server">
<ItemTemplate>
<img width="30px" src="<%#Eval("url") %>" />
</ItemTemplate>
</asp:Repeater>
</br>
</ItemTemplate>
</asp:Repeater>
code-behind:
public class ImageEntity
{
public string url { get; set; }
}
public partial class DataListSample : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
List<Tuple<ImageEntity, ImageEntity, ImageEntity>> listTuples = new List<Tuple<ImageEntity, ImageEntity, ImageEntity>>();
listTuples.Add(new Tuple<ImageEntity, ImageEntity, ImageEntity>(new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }, new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }, new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }));
listTuples.Add(new Tuple<ImageEntity, ImageEntity, ImageEntity>(new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }, new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }, new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }));
listTuples.Add(new Tuple<ImageEntity, ImageEntity, ImageEntity>(new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }, new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }, new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }));
listTuples.Add(new Tuple<ImageEntity, ImageEntity, ImageEntity>(new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }, new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }, new ImageEntity() { url = "http://www.google.com/images/srpr/logo4w.png" }));
this.rptRows.DataSource = listTuples;
this.rptRows.DataBind();
}
protected void rptRows_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
Repeater rptItems = (Repeater)e.Item.FindControl("rptItems");
Tuple<ImageEntity, ImageEntity, ImageEntity> items = (Tuple<ImageEntity, ImageEntity, ImageEntity>)e.Item.DataItem;
rptItems.DataSource = new List<ImageEntity>() { items.Item1, items.Item2, items.Item3 };
rptItems.DataBind();
}
}
}
Basically, what we are doing here is splitting up the list of URLs into a List of Tuples. The length of the List is the number of "rows" in the outer Repeater. The number of entities in the Tuple is the number of "columns" in the inner Repeater.
Each time we bind an item to the outer Repeater (rptRows_ItemDataBound) , we set the datasource of the inner Repeater to a newly generated list of the URL entities (ImageEntity).
Let me know if this is clear enough, I would be happy to expand and clarify any points that are unclear.
you can use a data list or repeater inside the item template of a listview and and in listview's layout template you can make any layout, div based , table or unsorted list
I have a ASP dynamic scaffolding project in which I am customizing a details view. In my data source I have a few fields containing HTML and I would like to display the rendered HTML on the page rather then the source HTML as it is currently doing. The control looks like this.
<tr>
<td class="DDLightHeader">
<asp:Label ID="lblStatementHtml" runat="server" Text="Statement" />
</td>
<td>
<asp:DynamicControl ID="dcStatementHtml" runat="server" DataField="StatementHtml" />
</td>
</tr>
I am confused on how to proceed since the default view for this control is the Text.ascx which is apparently nothing more then a literal (the same base control I use to render the HTML on my site. I am comfortable with creating a new FieldTemplate to render the HTML, but how can I force the html to render rather then display its source view.
To resolve the above issue I had to create anew FieldTemplate
HTML.ascx
<%# Control Language="C#" CodeBehind="HTML.ascx.cs" Inherits="ProductDynamicCMS.HTML" %>
<asp:Literal runat="server" ID="Literal1" />
HTML.cs
using System;
using System.Web.DynamicData;
using System.Web.UI;
namespace ProductDynamicCMS
{
public partial class HTML : FieldTemplateUserControl
{
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
object val = FieldValue;
if (val != null)
Literal1.Text = val.ToString();
}
public override Control DataControl
{
get
{
return Literal1;
}
}
}
}
Then applied the UIHint for this class to the field display in the details view template.
<tr>
<td class="DDLightHeader">
<asp:Label ID="lblStatementHtml" runat="server" Text="Statement" />
</td>
<td>
<asp:DynamicControl ID="dcStatementHtml" runat="server" DataField="StatementHtml" UIHint="HTML" />
</td>
</tr>
And all was well.
I've inherited an ASP.NET project that has poorly designed HTML; in one section, the <TR> tags are wrapped with an tag to allow for "click the row to view the information" functionality. The code is:
<asp:LinkButton ID="ViewArticle" runat="server" CommandName="Navigate" CommandArgument='<%# DataBinder.Eval(Container.DataItem, "id") %>' >
<tr runat="server" class="list_item">
<td>some data</td>
<td>some data</td>
<td>some data</td>
</tr>
</asp:LinkButton>
I'd like to do something like:
<tr runat="server" class="list_item" onclick="doRowPostbackFunction('<%# DataBinder.Eval(Container.DataItem, "id") %>');">
<td>some data</td>
<td>some data</td>
<td>some data</td>
</tr>
How do I go about tying a JavaScript onclick event to the codebehind?
Using jQuery you can do the following and trigger a postback:
<table>
<tr id="1">
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
</tr>
<tr id="2">
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
</tr>
<tr id="3">
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
</tr>
</table>
<script type="text/javascript">
$(function () {
$("table tr").click(function (e) {
//alert the row index that was clicked
alert($("table tr").index(this));
//alert the id of the row
alert($(this).attr("id"));
//submit the form...
});
});
</script>
OR use the onclick event of the row...
<tr onclick="doPostBack('<%#DataBinder.Eval(Container.DataItem, "id") %>')">
...and trigger a javascript function.
<script type="text/javascript">
function doPostBack(id)
{
//submit form
}
</script>
You could make your page (or control, if that's inside a control) implement IPostBackEventHandler interface and use ClientScriptManager.GetPostBackEventReference method (using Page.ClientScript propery to get a reference to ClientScriptManager) to get a js-method-call-string which will make a postback to your page. As a control argument to GetPostBackEventReference method use your page.
Then set onclick property of tr to that js-method-call-string.
Example
In aspx:
<table>
<tr onclick="<%= _jsPostBackCall %>;">
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
</table>
<h1>
<asp:Literal ID="litMessage" runat="server" />
</h1>
In codebehind:
public partial class _Default : System.Web.UI.Page, IPostBackEventHandler
{
protected String _jsPostBackCall;
protected void Page_Load(object sender, EventArgs e)
{
// "myTr" will be passed as an argument to RaisePostBackEvent method
_jsPostBackCall = ClientScript.GetPostBackEventReference(this, "myTr");
}
public void RaisePostBackEvent(string eventArgument)
{
switch (eventArgument)
{
case "myTr":
HandleTrClick();
break;
// you can add other controls that need postback processing here
default:
throw new ArgumentException();
}
}
private void HandleTrClick()
{
litMessage.Text = "Tr clicked.";
}
}
You can simply use
__doPostBack(eventName, eventArgs);
Here eventName is code-behind event handler
hows the best way to display comments/user data from a db using mvc?
do we just do our own for loop and manually display it or? will doing it this way cause paging problems in the future? any best methods or practice?
jquery?
thanks guys.
When I first started learning MVC, I put a lot of conditional code in the view to manage the display of the data and controls. However, once I figured out the benefit of HTML helpers, I found that it not only reduced the code in my views, but it also made it easier to test the resulting output.
As an example, this is a code fragment for an entry form that would appear in the finished HTML page:
<table class="listing">
<tr>
<td class="prompt">Last Name:</td>
<td><input id="LastName" name="LastName" value="Smith" /></td>
</tr>
<tr>
<td class="prompt">First Name:</td>
<td><input id="FirstName" name="FirstName" value="John" /></td>
</tr>
<tr>
<td class="prompt">Job Title:</td>
<td><input id="JobTitle" name="JobTitle" value="Manager" /></td>
</tr>
</table>
Building the view using standard MVC helpers would result in code that looks something like this:
<table class="listing">
<tr>
<td class="prompt">Last Name:</td>
<td><%= Html.TextBox("LastName", Model.LastName) %></td>
</tr>
<tr>
<td class="prompt">First Name:</td>
<td><%= Html.TextBox("FirstName", Model.FirstName) %></td>
</tr>
<tr>
<td class="prompt">Job Title:</td>
<td><%= Html.TextBox("JobTitle", Model.JobTitle) %></td>
</tr>
</table>
However, I was able to create HTML helpers that allowed me to make the view look like this:
<table class="listing">
<%= Html.Edit_LastName(Model.LastName) %>
<%= Html.Edit_FirstName(Model.FirstName) %>
<%= Html.Edit_JobTitle(Model.JobTitle) %>
</table>
Here are the HTML helpers:
private string Edit_Field(string prompt, string fieldName, string value)
{
string textBox = helper.TextBox(fieldName, value);
return string.Format("<tr><td class='prompt'>{0}</td><td>{1}</td></tr>", prompt, textBox);
}
public string Edit_LastName(this HtmlHelper helper, string value)
{
return EditField("Last Name:", "LastName", value);
}
public string Edit_FirstName(this HtmlHelper helper, string value)
{
return EditField("First Name:", "FirstName", value);
}
public string Edit_JobTitle(this HtmlHelper helper, string value)
{
return EditField("Job Title:", "JobTitle", value);
}
This method is not nearly as straightforward as the standard method, but if you have similar controls that are used on multiple views, this approach clearly helps with maintenance. For example, if you want to change the prompt text from "Job Title" to "Position", you just change the prompt string in the Edit_JobTitle method and the change is reflected in every view where that method is called.
is the best way to use client jquery
with tablesorter or server side for
loop?
I don't think there is a connection between these two. Anyways you have to use an iterator to get all the rows from the database. Then you can use jQuery plugin to view the data in pages.
Here is a nice implementation of this
Table Sorting, Paging and Filtering with jQuery
IMO, use the iterator. I use jquery plugins when I need a display format that is complex. jquery itslef is useful when you need to access/modify dom or make ajax calls. Paging shouldn't affect this decision or vice-versa.