Master C# Logo banner
Welcome to MasterCSharp.com - Master C#, the easy way... - by Saurabh Nandu

 


Discussion Forum Board Beta2

Add Comment
 

 
<div align="center"> <table border="0" width="90%" class="outline"> <tr> <td width="30%" class="outline"><b>Download File</b></td> <td width="10%" class="outline"><b>SDK</b></td> </tr> <tr> <td width="30%" class="outline"><a href="../../file/forumbeta2.zip" class="wbox">forumbeta2.zip</a> (39kb)</td> <td width="10%" class="outline">Beta2</td> </tr> </table> </div> <p> <span class=wboxheado>Introduction</span><br> This example updates the <a href="http://www.mastercsharp.com/article.aspx?ArticleID=13&amp;&amp;TopicID=2" class="wbox"> previous forum example</a> that I had written for beta1. A lot has changed since then, even though from outside the forum has the same looks internally a lot has changed! Due to this I have taken the trouble to elaborate this example into easy to understand pieces. This example will teach you to work with OleDb.NET, Databind DataGrid's to DataReaders, Custom Paging in DataGrid's and Templates in DataGrid's. This is a long and detailed one so get your jugs of coffee ready :)</p> <p><span class=wboxheado>Explanation</span><br> This example consists of 3 pages.<br> 1) forum.aspx - The Main Forum page. It lists all the topics in a DataGrid object with <b>Custom Paging</b> enabled. It also contains a form to post new topics.<br> 2) reply.aspx - This page is called from the forum page when you click on any topic. It contains the details of the topic as well as all replies made to the topic. This page contains the form to reply to the topic.<br> 3) postmessage.aspx - This page is called whenever any form is posted. It parses and stores the posted data into the Database.&nbsp;</p> <p><span class=wboxheado>Requirements</span><br> 1) .NET SDK beta 2 (Note: This example may not work with future versions of the SDK).<br> 2) Ms Access 2000 (Optional, only if you want to edit the database).<br> 3) ASP.NET support on your web server.</p> <p align="justify"><span class=wboxheado>Database Structure</span></p> <table width="90%" border="0" class="outline"> <tbody> <tr> <td width="100%" colSpan="3" class="outline"><span class=wboxhead>Table Name - newpost / This table will contain the new topics posted.</span></td> </tr> <tr> <td width="20%" class="outline"><b>Column Name&nbsp;</b></td> <td width="15%" class="outline"><b>Data Type</b></td> <td class="outline"><b>Description</b></td> </tr> <tr> <td width="20%" class="outline">postid&nbsp;</td> <td width="15%" class="outline">AutoNumber</td> <td class="outline">The primary key field. The unique id for each new topic.</td> </tr> <tr> <td width="20%" class="outline">name</td> <td width="15%" class="outline">Text</td> <td class="outline">The name of the author of the message.</td> </tr> <tr> <td width="20%" class="outline">email</td> <td width="15%" class="outline">Text</td> <td class="outline">E-mail address of the author.</td> </tr> <tr> <td width="20%" class="outline">subject</td> <td width="15%" class="outline">Text</td> <td class="outline">Subject of the message.</td> </tr> <tr> <td width="20%" class="outline">ip</td> <td width="15%" class="outline">Text</td> <td class="outline">IP address of the author.</td> </tr> <tr> <td width="20%" class="outline">dt</td> <td width="15%" class="outline">Text</td> <td class="outline">Date / Time of the Post</td> </tr> <tr> <td width="20%" class="outline">message</td> <td width="15%" class="outline">Memo</td> <td class="outline">Message posted.</td> </tr> <tr> <td width="20%" class="outline">replies</td> <td width="15%" class="outline">Integer</td> <td class="outline">Number of replies to the post (if any)</td> </tr> <tr> <td width="20%" class="outline">views</td> <td width="15%" class="outline">Integer</td> <td class="outline">Number of times the message has been viewed.&nbsp;</td> </tr> </tbody> </table> <br> <table width="90%" border="0" class="outline"> <tbody> <tr> <td width="99%" colSpan="3" class="outline"><span class=wboxhead>Table Name- reply / This table will contain the replies made to the new topics.</span></td> </tr> <tr> <td width="20%" class="outline"><b>Column Name</b></td> <td width="15%" class="outline"><b>Data Type</b></td> <td class="outline"><b>Description</b></td> </tr> <tr> <td width="20%" class="outline">replyid</td> <td width="15%" class="outline">AutoNumber</td> <td class="outline">The primary key field. The unique id for each reply.</td> </tr> <tr> <td width="20%" class="outline">name</td> <td width="15%" class="outline">Text</td> <td class="outline">Name of the author.</td> </tr> <tr> <td width="20%" class="outline">email</td> <td width="15%" class="outline">Text</td> <td class="outline">E-mail address of the author.</td> </tr> <tr> <td width="20%" class="outline">subject</td> <td width="15%" class="outline">Text</td> <td class="outline">Subject of the post</td> </tr> <tr> <td width="20%" class="outline">ip</td> <td width="15%" class="outline">Text</td> <td class="outline">IP of the author.</td> </tr> <tr> <td width="20%" class="outline">dt</td> <td width="15%" class="outline">Text</td> <td class="outline">Date / Time of post.</td> </tr> <tr> <td width="20%" class="outline">message</td> <td width="15%" class="outline">Memo</td> <td class="outline">Message posted.</td> </tr> <tr> <td width="20%" class="outline">postid</td> <td width="15%" class="outline">Integer</td> <td class="outline">postid from the &quot;newpost&quot; table for which this message is a reply.</td> </tr> </tbody> </table><P><span class=wboxheado>Code</span><BR>1) <b> forum.aspx</b> :- The main forum page. (Only relevant pieces shown)&nbsp;<br> This page is one of the most important pages, read this code carefully! </P> <table border="0" width="100%" class="code" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <pre>&lt;%@ Page Language=&quot;C#&quot; EnableSessionState=&quot;False&quot; %&gt; &lt;%@ Import Namespace=&quot;System.Data.OleDb&quot; %&gt; &lt;%@ Import Namespace=&quot;System.Data&quot; %&gt; &lt;%@ Import Namespace=&quot;System&quot; %&gt; &lt;html&gt;&lt;head&gt; &lt;title&gt;Welcome to My Forum!&lt;/title&gt; &lt;script language=&quot;C#&quot; runat=&quot;server&quot; &gt; int startIndex; void Page_Load(Object Src, EventArgs E) { <span class=cmt>//check if the page is loaded for the first time.</span> if(!IsPostBack) { <span class=cmt>//Call the Binding Method</span> Binding() ; } } ..... ...... &lt;/script&gt;</pre> </td> </tr> </table><br>Above, after importing the necessary namespaces, I have declared a global Integer variable '<b>startIndex</b>' whose work we shall see a bit later. Next I declare the '<b>Page_Load</b>' method, this method is an Event Handler of the <b> Page</b> class and gets fired automatically every time the page gets loaded. Within this method I check if the page is being loaded for the first time by checking the '<b>IsPostBack</b>' property of the Page class. If the Page is called for the first time, 'IsPostBack' returns a 'false' and if the page is reloaded, it returns a 'true'. Since I want the DataGrid to be databound from the 'Page_Load' method only when the Page is first loaded, I call the '<b>Binding</b>' method (defined a bit later) within the 'if' block. <p>&nbsp;</p> <table border="0" width="100%" class="code" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <pre> public void DataGrid_Updt(object sender, DataGridPageChangedEventArgs e) { <span class=cmt>//store the next page index</span> DataGrid1.CurrentPageIndex = e.NewPageIndex; <span class=cmt>//update the variable</span> startIndex = (DataGrid1.CurrentPageIndex * DataGrid1.PageSize); <span class=cmt>//call the method to data bind the DataGrid</span> Binding(); }</pre> </td> </tr> </table><br>The '<b>DataGrid_Updt</b>' method defined above gets called every time the DataGrid is Paged. Generally in an active forum hundreds topics are listed everyday. Displaying all the topics to every user is a waste of bandwidth, users time, as well as the time taken to load the page will be very very high! So we use Paging support in the DataGrid object, whereby only fixed number of records are displayed on each page and a link to other pages like (1,2,3...) is given below the grid. This saves users time and bandwidth.&nbsp;<br> When the user changes the page, '<b>PageIndexChanged</b>' Event is fired by the DataGrid. In my example the above method is an Event Handler for this Event. You will also note that this method has one different argument of the type '<b>DataGridPageChangedEventArgs</b>'. This argument contains some important information regarding the DataGrid Page. I use the '<b>NewPageIndex</b>' property to find out the Page number the user has clicked on the DataGrid. So if the user clicks on the third page, this variable will return the value '3'. I set the '<b>CurrentPageIndex</b>' property of the DataGrid that denotes the current page being displayed to the value returned by the 'NewPageIndex'.&nbsp;<br> The 'startIndex' variable which I had declared as global (remember!) is set to the value obtained by multiplying the 'CurrentPageIndex' and the '<b>PageSize</b>' of the DataGrid. 'CurrentPageIndex' denotes the current page number being viewed while the 'PageSize' property denotes the total number of records shown per page. So if the user click's on Page 3, then we store (3*20)&nbsp; = 60 in the variable 'startIndex' (Note: I have set the 'PageSize' to 20, so I am using the value 20 above). Why do I do this? Answer to this a bit later....&nbsp;<br> Next, the 'Binding' method is given a call. As you know, this method will databind the DataGrid.<br> <br> One point I would like to make here is, that when the user click's on a new page number to change the page, the page gets refreshed and the 'Page_Load' method is called first, why? (I have answered the question above, read carefully) and then the 'DataGrid_Updt' method is called. If within the 'Page_Load' method I would not have put a check on 'IsPostBack' property and directly declared the 'Binding' method. The code would still work, but it would be a waste of resources since in the 'DataGrid_Updt' too calls the same 'Binding' method after setting some different arguments and the DataGrid would get re-binded twice! This is a common error made my many programmers (I too used to make it!), so always remember to check for 'IsPostBack' property in the 'Page_Load' method before DataBinding while using DataGrid's ! <p>&nbsp;</p> <table border="0" width="100%" class="code" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <pre> public void Binding() { <span class=cmt>//Connection string</span> string strConn=@&quot;Provider=Microsoft.Jet.OLEDB.4.0 ;Data Source=&quot;; strConn+=Server.MapPath(&quot;.\\db\\board.mdb&quot;); <span class=cmt>//Make a new connection</span> OleDbConnection myConn = new OleDbConnection(strConn) ; string strCom; <span class=cmt>//Check is the Page is loaded for the first time</span> if(!IsPostBack) { <span class=cmt>//Set the variable to its default value</span> startIndex =0; <span class=cmt>//SQL statement to choose the last record</span> strCom = &quot;SELECT TOP 1 postid FROM newpost ORDER BY postid DESC&quot; ; <span class=cmt>//Create a Command</span> OleDbCommand countCommand = new OleDbCommand(strCom, myConn); <span class=cmt>//Open the connection</span> myConn.Open(); <span class=cmt>//Create a DataReader</span> OleDbDataReader countReader = countCommand.ExecuteReader(); <span class=cmt>//Check if the DataReader has any </span><span class=cmt>records</span> if(!countReader.Read()) { <span class=cmt>//Set VirtualItemCount to 0 since no records exist</span> DataGrid1.VirtualItemCount=0; } else { <span class=cmt>//Set VirtualItemCount to the total number of records in the table</span> DataGrid1.VirtualItemCount= countReader.GetInt32(0); } <span class=cmt>//Close the connection</span> myConn.Close(); } <span class=cmt>//SQL statement to choose just 20 records in Descending order </span> strCom = &quot;SELECT TOP 20 postid ,subject ,name ,replies ,views ,dt FROM newpost &quot;; strCom+= &quot;WHERE postid &lt; &quot;+(DataGrid1.VirtualItemCount-(startIndex-1) ); strCom+=&quot; ORDER BY postid DESC&quot; ; OleDbCommand forumCommand = new OleDbCommand(strCom, myConn); myConn.Open(); OleDbDataReader forumReader = forumCommand.ExecuteReader(); <span class=cmt>//Set the DataSource</span> DataGrid1.DataSource = forumReader ; <span class=cmt>//DataBind the grid</span> DataGrid1.DataBind(); myConn.Close(); }</pre> </td> </tr> </table><br>Before diving into the above code, I would like to make a few comments first. <p><span class=wboxheado>DataSet vs DataReader</span><br> When we started programming with .NET SDK beta1, we were introduced to the idea of DataSet's. A DataSet object is in-memory representation of the database, but it's always disconnected from the database. Also the DataSet object does not have any idea of the Data Source from which the Data has been populated into it. Its neutral to the source of the data, and data can be either fed into it through DataAdapters (DataSetCommand in beta1) or can be programmatically entered. The DataSet object is so powerful and easy to use that everyone started using it instantly.<br> When .NET SDK beta2 was released, Microsoft has clearly indicated that, even though DataSet's are powerful and very customizable, they should be used with caution! Since DataSet are created in-memory, they have a high memory requirement, and bring down the performance of your Web Application. As against DataSet, a DataReader object represents a fast, forward-only record cursor, which can be used to only read data in a systematic manner. Since the DataReader reads one record at a time its memory requirement is very low and its speed is very high.&nbsp;<br> Also note that when a DataSet object is populated through a DataAdapter, internally a DataReader is created to populate the DataSet. So whenever you are using a DataSet, a DataReader object is always created! Hence DataReader's offer a better performance for your Applications and they should be used wherever the need is to just display the Data without much customization. Hence I too will be using a DataReader in this example!</p> <p><span class=wboxheado>DataReader and DataGrid Paging</span><br> Above I have explained the need and use of Paging in DataGrid's. While data binding DataReader's to DataGrid's with just Paging enabled (through the 'AllowPaging' property) you get a error, Why? The reason for this is that a DataReader does not implement the '<b>ICollection</b>' Interface. The 'ICollection' Interface defines a property called '<b>Count</b>' which helps the DataGrid object know at runtime the number of records present and hence it can compute the number of pages to show. i.e. If the DataGrid object knows that there are 200 records and the 'PageSize' (number of records displayed per page) is set to 20 then it will draw links for pages 1 to 10 (200/20=10, right !!! :) ).<br> <br> You might think that while using DataSet's you don't get such a error even though DataSet's also don't implement the 'ICollection' Interface? (Rub your eye's hard!!) While using DataSet's we never DataBind to the DataSet, we always data bind to a DataView object, remember!! And the <b> DataView</b> object implements the 'ICollection' Interface so we have never faced this problem!<br> <br> So what to do now? Well we start of by setting the '<b>AllowPaging</b>' and '<b>AllowCustomPaging</b>' properties of the DataGrid to '<b>true</b>' indicating that we want Paging support in our grid, but we will manually handle the Paging code. We also wire-up the '<b>PagingIndexChanged</b>' event through which we shall manually handle paging of the DataGrid.<br> Next we have to set the '<b>VirtualItemCount</b>' property of the DataGrid <i> programmatically</i> (it cannot be set directly with the DataGrid declaration) to the total number of records present in the Table.&nbsp;<br> One advantage this approach gives us is that since actually only some records are shown per page and a fresh set of records are retrieved every time the page changes, in our custom paging code we can set the SQL Query in such a way that it only retrieves the data that will be shown in the DataGrid. This way we save a lot of traffic on our network!</p> <p>I hope you have been able to gasp some of the changes from beta1 to beta2. Now time to kick some heavy code! Re-fill your coffee cups and go through the above code of the 'Binding' method.<br> Let's start... First I declare a '<b>OleDbConnection</b>' variable and then I have put another If-Block which checks if the Page is loaded for the first time. If '!IsPostBack' (not PostBack) evaluates to true, that means&nbsp; that the page is being loaded from the first time. Within this If-Block, I initialize the global integer variable 'startIndex' to zero, its default value, then I have written a SQL statement, which will return only the '<b>postid</b>' column of the last record in the database. <i> Why am I doing this?</i> As I had mentioned in the &quot;<i>DataReader and DataGrid Paging</i>&quot; section, that in order to enable custom paging in a DataReader bound DataGrid you have to set the 'VirtualItemCount' property of the DataGrid to the total number or records. If you check the schema of the '<b>newpost</b>' table you will find that the 'postid' column is of the type '<b>Auto Number</b>' and contains sequential numbers in increasing order. So if we get the 'postid' of the last record, we can get the total number of records present in the database, since the 'postid' of the last record will be equal to the number of records in the table.<br> <br> One possible problem to this approach might be that if in the future someone deletes a record from the table for moderation purpose, then we will have change this approach. Since this feature is yet not implemented, I will continue with this approach.&nbsp;<br> <br> Finally, a OleDBCommand and OleDbDataReader objects are made and the command is executed. Following it is one more If-block. This block check's if the '<b>Read</b>' method of the DataReader returned any records, if so then a <i> true</i> is returned. I have implemented this check since the first time you run this code, there are no records to be read, at this time attempting to perform any operations on the DataReader will generate an exception. So in the If-block, if this condition evaluates to false i.e. no records have been read then I set the 'VirtualItemCount' property of the DataGrid to zero, else its set to the total number of records in the table, represented by the 'postid' field of the last record. Note that the 'VirualItemCount' is only set once, when the page is first loaded.&nbsp;<br> <br> Moving ahead, I have formed one more SQL statement, which actually will retrieve the data to be shown in the DataGrid. This statement looks a bit too weird since I am trying to achieve many things from this statement. for simplicity purpose I will break down this statement into parts.<br> <br> <i>&quot;SELECT TOP 20 postid ,subject ,name ,replies ,views ,dt FROM newpost&quot;</i>&nbsp; - This part selects the respective fields from the 'newpost' table. The directive 'TOP 20' only returns 20 records. If you remember I had mentioned before that you can customize the SQL statement in such a way that it should return only those records that have to be displayed on the page. Since the 'PageSize' property of our DataGrid is 20 I have chosen only 'TOP 20' records from the database. <br> <br> <i>&quot;WHERE postid &lt; &quot;+(DataGrid1.VirtualItemCount-(startIndex-1) )&quot;</i>&nbsp; - This is where the real magic of the global variable 'startIndex' comes. In order to achieve our goal of returning only the necessary number of records (20), I have created a condition where I subtract the current value of 'startIndex' from the total number of rows (represented by the 'VirtualItemCount') property. If you would recall, in the 'DataGrid_Updt' I first update the 'startIndex' field and then I call this method. So say for example, the user clicked on 'Page 3', the page will refresh, and call the 'Page_Load' method, right? (I hope ur awake!!) and then it will call the 'DataGrid_Updt' method. In this method the 'startIndex' variable will be set to 60 (3*20, where 3 is the page number and 20 is the number of records displayed per page). Next the 'Binding' method will be called from the 'DataGrid_Updt' method. Here the above SQL statement will be evaluated to,&nbsp;<br> <i>&quot;WHERE postid &lt; &quot; +(200 - (60 -1))&quot;</i>&nbsp; - (assuming the total number of records being 200)<br> &nbsp;&quot;WHERE postid &lt; 141&quot;&nbsp; - hence all records below 141 will be selected.&nbsp;<br> Also applying the above described &quot;TOP 20&quot; condition only records from 120 to 140 (total 20 records) get selected!! Thus we achieve our target of only retrieving 20 records from the Database!!!!!&nbsp;<br> <br> <i>&quot;ORDER BY postid DESC&quot;</i>&nbsp; - Lastly we sort these 20 selected records in descending order, Why? Simply since we want the latest/newest post to appear first and the oldest post to appear last!<br> <br> Once the SQL statement is ready, be make a command and DataReader object and execute the command. The derived reader is then databound to the DataGrid, displaying the records fetched by us. If you would observe carefully, while I have made multiple commands and readers, I have used the same instance of OleDbConnection class, just opening it and closing it. This is because there is a huge performance gain while using a single connection object to perform various activities rather than creating a new instance every time you want to connect to the database.<br> Now wasn't that easy ..... (I am kidding .... :))&nbsp;<br> </p> <table border="0" width="100%" class="code" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <pre>public void Submit_Click(Object sender, EventArgs e) { <span class=cmt>//proceed only if the page is valid</span> if(Page.IsValid){ DateTime now = DateTime.Now ; errmess.Text=&quot;&quot; ; string req = &quot;name=&quot;+ System.Web.HttpUtility.UrlEncode(name.Text, System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;email=&quot;+ System.Web.HttpUtility.UrlEncode(email.Text, System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;subject=&quot;+ System.Web.HttpUtility.UrlEncode(subject.Text, System.Text.Encoding.UTF8); <span class=cmt>//Get the HostAddress of the Author</span> req+=&quot;&amp;&amp;ip=&quot;+ System.Web.HttpUtility.UrlEncode(Request.UserHostAddress.ToString(), System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;date=&quot;+ System.Web.HttpUtility.UrlEncode(now.ToString(), System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;message=&quot;+ System.Web.HttpUtility.UrlEncode(message.Text, System.Text.Encoding.UTF8); <span class=cmt>//A 'yes' is used below to tell the postmessage page that this is a new topic </span> req+=&quot;&amp;&amp;newpost=&quot;+ System.Web.HttpUtility.UrlEncode(&quot;yes&quot;, System.Text.Encoding.UTF8); <span class=cmt>//call the postmessage.aspx page and append the query to it.</span> Response.Redirect(&quot;postmessage.aspx?&quot; + req); } else { errmess.Text=&quot;Fill in all the Required Fields before Posting!&lt;br&gt;&quot; ; } }</pre> </td> </tr> </table><br>The above method is called when a form (code shown below) is submitted. In ASP.NET 'Form's' that run at sever behave a bit differently than the forms we are used to in HTML and ASP. In ASP.NET we have the concept of <b>Post-Back</b>, i.e instead of sending the form details to some other page, the same page gets posted/called again and it can handle all the logic for updating/inserting the data into the database. Example of this is that when you click on any page number in the DataGrid, the same page gets called again, but with the necessary coding you can change the contents of the page. In my example to have maintainability of posting the form from various pages, I did not want this, rather I wanted to have the same old functionality that HTML/ASP gave us. I found 2 solutions to solve my problem:<br> 1) Use a normal &lt;form&gt; tag without the 'runat=server' attribute and specify its action attribute to the new page. There was one drawback to this solution, I could no longer the Form Validating Web Controls like '<b>RequiredFieldValidator</b>' etc which make form validation task in ASP.NET very easy!<br> 2) The second solution is to declare a 'Form' to run at server, and in the Event Handling code, take the all the values of the form, append it as a query string manually and call the next page. I have taken this path. Just one last hitch to this is that while appending the query after a page you should convert it essentially to the UTF-8 format. So in the above method I take all the fields from the Form, convert it into UTF-8 format and finally redirect the response to the 'postmessage.aspx' page after appending all the form contents as a query. Beta1 users note that the 'Page.Navigate' method available in beta1 has been removed in beta2 :(. <p>&nbsp;</p> <table border="0" width="100%" class="code" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <pre>&lt;form method=&quot;post&quot; runat=&quot;server&quot; ID=Form1&gt; <span class=cmt>&lt;%-- The DataGrid settings. Its very interesting how much you can play with it --%&gt;</span> &lt;asp:DataGrid id=DataGrid1 runat=&quot;server&quot; ForeColor=&quot;Black&quot; OnPageIndexChanged=&quot;DataGrid_Updt&quot; PageSize=&quot;20&quot; AllowPaging=&quot;True&quot; width=&quot;80%&quot; autogeneratecolumns=&quot;False&quot; AllowCustomPaging=&quot;True&quot; &gt; &lt;PagerStyle BackColor=&quot;Coral&quot; Mode=&quot;NumericPages&quot;&gt; &lt;/PagerStyle&gt; &lt;AlternatingItemStyle BorderColor=&quot;#FFC080&quot; BackColor=&quot;#FF9966&quot;&gt; &lt;/AlternatingItemStyle&gt; &lt;FooterStyle ForeColor=&quot;White&quot; BackColor=&quot;DarkOrange&quot;&gt; &lt;/FooterStyle&gt; &lt;ItemStyle BackColor=&quot;Moccasin&quot;&gt; &lt;/ItemStyle&gt; &lt;HeaderStyle Font-Bold=&quot;True&quot; ForeColor=&quot;White&quot; BackColor=&quot;Coral&quot;&gt; &lt;/HeaderStyle&gt; <span class=cmt>&lt;%-- I am setting up the Individual columns myself using Templates --%&gt;</span> &lt;Columns&gt; <span class=cmt>&lt;%-- Manipulate the subject entry so that it contains a link to the reply page --%&gt;</span> &lt;asp:TemplateColumn HeaderText=&quot;Subject&quot; itemstyle-width=50%&gt; &lt;ItemTemplate&gt; &lt;asp:Label runat=&quot;server&quot; Text= '&lt;%#&quot;&lt;a href=reply.aspx?postid=&quot;+DataBinder.Eval(Container, &quot;DataItem.postid&quot;)+&quot;&gt;&quot; +DataBinder.Eval(Container, &quot;DataItem.subject&quot;)+&quot;&lt;/a&gt;&quot; %&gt;' ID=Label2&gt;&lt;/asp:Label&gt; &lt;/ItemTemplate&gt; &lt;/asp:TemplateColumn&gt; &lt;asp:TemplateColumn HeaderText=&quot;Author Name&quot; itemstyle-width=20%&gt; &lt;ItemTemplate&gt; &lt;asp:Label runat=&quot;server&quot; Text='&lt;%# DataBinder.Eval(Container, &quot;DataItem.name&quot;) %&gt;' ID=Label3&gt;&lt;/asp:Label&gt; &lt;/ItemTemplate&gt; &lt;/asp:TemplateColumn&gt; &lt;asp:TemplateColumn HeaderText=&quot;Replies&quot; itemstyle-width=10%&gt; &lt;ItemTemplate&gt; &lt;asp:Label runat=&quot;server&quot; width=10% Text='&lt;%# DataBinder.Eval(Container, &quot;DataItem.replies&quot;) %&gt;' ID=Label4&gt; &lt;/asp:Label&gt; &lt;/ItemTemplate&gt; &lt;/asp:TemplateColumn&gt; &lt;asp:TemplateColumn HeaderText=&quot;Views&quot; itemstyle-width=10%&gt; &lt;ItemTemplate&gt; &lt;asp:Label runat=&quot;server&quot; width=10% Text='&lt;%# DataBinder.Eval(Container, &quot;DataItem.views&quot;) %&gt;' ID=Label5&gt; &lt;/asp:Label&gt; &lt;/ItemTemplate&gt; &lt;/asp:TemplateColumn&gt; &lt;asp:TemplateColumn HeaderText=&quot;Date of Post&quot; itemstyle-width=10%&gt; &lt;ItemTemplate&gt; &lt;asp:Label runat=&quot;server&quot; width=10% Text=' &lt;%# DateTime.Parse(DataBinder.Eval(Container, &quot;DataItem.dt&quot;).ToString()).ToShortDateString() %&gt;' ID=Label6&gt; &lt;/asp:Label&gt; &lt;/ItemTemplate&gt; &lt;/asp:TemplateColumn&gt; &lt;/Columns&gt; &lt;/asp:DataGrid&gt;</pre> </td> </tr> </table><br>Above, is the very interesting definition of the DataGrid, that will display the data from the 'newpost' table. Firstly, I wire-up the Event Handler for the '<b>OnPageIndexChange</b>' Event, set the '<b>PageSize</b>' property to 20 and the '<b>AllowPaging</b>' / '<b>AllowCustomPaging</b>' properties to '<b>true</b>' since I want to enable paging in my grid with my custom method. I also set the '<b>AutoGenerateColumns</b>' property to '<b>false</b>' since I want to manually handle the creation of each column.<br> Next, I define a few Templates, Templates allow you to easily customize different parts of the DataGrid to suit your needs. The '<b>PagerStyle</b>', '<b>AlternatingItemStyle</b>', '<b>FooterStyle</b>', '<b>ItemStyle</b>' and the '<b>HeaderStyle</b>' templates are used to modify the display of the respective parts of the DataGrid. Under the '<b>Columns</b>' template we define individual settings for each column. The '<b>TemplateColumn</b>' control (note its a control not a template!) is used within the 'Columns' template to represent each column. The '<b>ItemTemplate</b>' template within each is 'TemplateColumn' control used to define the custom display. Under the 'ItemTemplate' template we can include various other controls and program them to display required output. In the above code I have done some customization to each of the columns within the 'ItemTemplate' template. Beta1 users note how the different template names have changed, they are much more self-explanatory and easy to use in beta2!! Novice users should note that I have encapsulated the DataGrid within a ASP.NET 'Form' that run's at server. This is very important, or your DataGrid Paging won't work!! <p>&nbsp;</p> <table border="0" width="100%" class="code" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <pre>&lt;table border=&quot;0&quot; width=&quot;80%&quot; align=&quot;center&quot;&gt; &lt;tr &gt; &lt;td class=&quot;fohead&quot; colspan=2&gt;&lt;b&gt;Post New Topic&lt;/b&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=&quot;folight&quot; &gt; &lt;td&gt;Name :&lt;/td&gt; &lt;td &gt;&lt;asp:textbox text=&quot;&quot; id=&quot;name&quot; runat=&quot;server&quot; /&gt; &lt;asp:RequiredFieldValidator ControlToValidate=name display=static runat=server&gt; *&lt;/asp:RequiredFieldValidator&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt;E-Mail&amp;nbsp;:&lt;/td&gt; &lt;td&gt;&lt;asp:textbox text=&quot;&quot; id=&quot;email&quot; runat=&quot;server&quot;/&gt; &lt;asp:RequiredFieldValidator ControlToValidate=email display=static runat=server&gt; *&lt;/asp:RequiredFieldValidator&gt; &lt;asp:RegularExpressionValidator runat=&quot;server&quot; ControlToValidate=&quot;Email&quot; ValidationExpression=&quot;[\w-]+@([\w-]+\.)+[\w-]+&quot; Display=&quot;Static&quot; Font-Name=&quot;verdana&quot; Font-Size=&quot;10pt&quot; ErrorMesage=&quot;Please enter a valid e-mail address&quot;&gt; &lt;/asp:RegularExpressionValidator&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt; Subject:&lt;/td&gt; &lt;td&gt;&lt;asp:textbox test=&quot;&quot; id=&quot;subject&quot; width=200 runat=&quot;server&quot;/&gt; &lt;asp:RequiredFieldValidator ControlToValidate=subject display=static runat=server&gt; *&lt;/asp:RequiredFieldValidator&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt;Message&amp;nbsp;:&lt;/td&gt; &lt;td&gt; &lt;asp:TextBox id=message runat=&quot;server&quot; Columns=&quot;30&quot; Rows=&quot;15&quot; TextMode=&quot;MultiLine&quot;&gt;&lt;/asp:TextBox&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=folight&gt; &lt;td colspan=2&gt; &lt;asp:Button class=fodark id=write onClick=Submit_Click runat=&quot;server&quot; Text=&quot;Submit&quot;&gt; &lt;/asp:Button&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/table&gt; &lt;/form&gt;</pre> </td> </tr> </table><br>The final piece of the forum.aspx page is the form that can be used to post new topics to the forum. Nothing special here except a normal form and a few form validators.<br> Phew! One down 2 to go......&nbsp; Take a round, freshen your mind... and COME BACK!!<br> <p>2) <b> reply.aspx</b> : The topic viewing and replying page.<br> <br> I am not describing this page in detail since it just retrieves some content from the database and updates the necessary fields. Later it displays the content in a tabular form. One exercise I have left for you to solve is to convert the code to use a DataReader and a Repeater.&nbsp;</p> <table border="0" width="100%" class="code" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <pre>&lt;%@ Page Language=&quot;C#&quot; EnableSessionState=&quot;False&quot; %&gt; &lt;%@ Import Namespace=&quot;System.Data&quot; %&gt; &lt;%@ Import Namespace=&quot;System.Data.OleDb&quot; %&gt; &lt;html&gt;&lt;head&gt; &lt;title&gt;Post New Topic.&lt;/title&gt; &lt;script Language=&quot;C#&quot; runat=&quot;server&quot;&gt; DataSet ds ,rs; DataRow dr ; string postid ; public void Page_Load(object sender , EventArgs e) { <span class=cmt>//Check if the page is Post Back </span> if(!Page.IsPostBack) { <span class=cmt>//Get the postid from the Query string</span> postid = Request.Params[&quot;postid&quot;] ; if(postid!=null) { <span class=cmt>//Database connection string.</span> string strConn=@&quot;Provider=Microsoft.Jet.OLEDB.4.0;&quot;; strConn+=&quot;Data Source=&quot;+Server.MapPath(&quot;.\\db\\board.mdb&quot;) ; <span class=cmt>//Make a connection to the Database</span> OleDbConnection myConn = new OleDbConnection(strConn) ; <span class=cmt>//string to select the records from the newpost table</span> string strCon =&quot;SELECT subject, name, email, message ,dt FROM newpost &quot;; strCon+=&quot;WHERE postid=&quot;+postid ; <span class=cmt>//set a OleDbDataAdapter </span> OleDbDataAdapter myCommand =new OleDbDataAdapter(strCon,strConn); ds = new DataSet(); <span class=cmt>//Fill the DataSet</span> myCommand.Fill(ds,&quot;newpost&quot;) ; <span class=cmt>//Get the Row at position '0' and store it in a DataRow object //Why put into a DataRow ? Its easy to access data from a DataRow</span> dr = ds.Tables[&quot;newpost&quot;].Rows[0] ; <span class=cmt>//Get the &quot;subject&quot; from the DataRow and set it up in the post reply //form's subject field </span> subject.Text=&quot;Re:&quot;+dr[&quot;subject&quot;].ToString() ; <span class=cmt>//Select the replies to the post from the reply table</span> strCon =&quot;SELECT name , email, subject, message ,dt FROM reply &quot;; strCon+=&quot;WHERE postid=&quot;+postid ; <span class=cmt>//Make a new OleDbDataAdapter and DataSet for the reply table</span> OleDbDataAdapter myCommand2 =new OleDbDataAdapter(strCon,strConn); rs = new DataSet() ; <span class=cmt>//fill the DataSet</span> myCommand2.Fill(rs, &quot;reply&quot;) ; <span class=cmt>//Code to update the &quot;views&quot; field for the newpost Table //Select the views field from the table for a given postid</span> strCon =&quot;SELECT views FROM newpost WHERE postid = &quot;+postid ; <span class=cmt>//Make a OleDbCommand here since we want a OleDbDataReader later </span> OleDbCommand vicomm = new OleDbCommand(strCon, myConn) ; myConn.Open(); OleDbDataReader reader ; <span class=cmt>//execute the statement and create a OleDbDataReader</span> reader = vicomm.ExecuteReader() ; <span class=cmt>//Read the First record (there can only be one record remember !)</span> reader.Read() ; <span class=cmt>//Get a &quot;Int32&quot; value from the first Column </span> int i = reader.GetInt32(0) ; <span class=cmt>//Increase the views count</span> i++ ; reader.Close() ; <span class=cmt>//Update the newpost table with the new views value</span> strCon =&quot;UPDATE newpost SET views = &quot;+i+&quot; WHERE (postid= &quot;+postid+&quot;)&quot; ; <span class=cmt>//since we are using the same OleDbCOmmand object for this statement //too, so set the CommandText property</span> vicomm.CommandText = strCon ; <span class=cmt>//Since this statement will result in no output we use &quot;ExecuteNonQuery()&quot;</span> vicomm.ExecuteNonQuery() ; <span class=cmt>//close the connection</span> myConn.Close(); } } } <span class=cmt>// This method is called when the submit button is clicked </span> public void Submit_Click(Object sender, EventArgs e) { <span class=cmt>//Get the postid</span> postid = Request.Params[&quot;postid&quot;] ; <span class=cmt>//proceed only if Page is valid</span> if(Page.IsValid){ DateTime now = DateTime.Now ; errmess.Text=&quot;&quot; ; <span class=cmt>//We have to call the postmessage.aspx page with a query to post the data //Hence we have to first build the custom query from the Data posted by the user //also since we are using a query we have to encode the data into UTF8 format</span> string req = &quot;name=&quot;+ System.Web.HttpUtility.UrlEncode(name.Text, System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;email=&quot;+ System.Web.HttpUtility.UrlEncode(email.Text, System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;subject=&quot;+System.Web.HttpUtility.UrlEncode(subject.Text, System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;ip=&quot;+System.Web.HttpUtility.UrlEncode(Request.UserHostAddress.ToString(), System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;date=&quot;+ System.Web.HttpUtility.UrlEncode(now.ToString(), System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;message=&quot;+ System.Web.HttpUtility.UrlEncode(message.Text, System.Text.Encoding.UTF8); <span class=cmt>//Encode &quot;no&quot; to indicate that the post is not a new post //but its a reply to a earlier message</span> req+=&quot;&amp;&amp;newpost=&quot;+ System.Web.HttpUtility.UrlEncode(&quot;no&quot;, System.Text.Encoding.UTF8); req+=&quot;&amp;&amp;previd=&quot;+ System.Web.HttpUtility.UrlEncode(postid, System.Text.Encoding.UTF8); //Call the postmessage page with our custom query Response.Redirect(&quot;postmessage.aspx?&quot; + req); } else { errmess.Text=&quot;Fill in all the Required Fields !&quot; ; } } &lt;/script&gt; &lt;LINK href=&quot;mystyle.css&quot; type=text/css rel=stylesheet&gt;&lt;/head&gt; &lt;body topmargin=&quot;0&quot; leftmargin=&quot;0&quot; rightmargin=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot;&gt; <span class=cmt>&lt;%-- Include a header file 'header.inc' --%&gt;</span> &lt;!-- #Include File=&quot;header.inc&quot; --&gt; &lt;br&gt; &lt;div align=center&gt; &lt;table border=0 width=80% cellspacing=2&gt; &lt;tr class=fohead&gt;&lt;th width=20%&gt;Author Name&lt;/th&gt; &lt;th width=80%&gt;Message&lt;/th&gt;&lt;/tr&gt; <span class=cmt>&lt;%-- Below I am encapsulating the email of the author over the name of the author so that when you click on the author a e-mail gets sent to him Also I am getting the DateTime from the DataBase and Displaying the Date and Time separately --%&gt; </span> &lt;tr class=folight&gt;&lt;td rowspan=2 align=&quot;center&quot;&gt; &lt;%= &quot;&lt;a href=mailto:&quot;+dr[&quot;email&quot;]+&quot;&gt;&quot;+dr[&quot;name&quot;]+&quot;&lt;/a&gt;&quot; %&gt;&lt;br&gt; &lt;font size=1&gt;&lt;%= DateTime.Parse(dr[&quot;dt&quot;].ToString()).ToShortDateString() %&gt;&lt;br&gt; &lt;%= DateTime.Parse(dr[&quot;dt&quot;].ToString()).ToShortTimeString() %&gt;&lt;/font&gt; &lt;/td&gt; &lt;td&gt;&lt;b&gt;Subject: &lt;/b&gt;&lt;%=dr[&quot;subject&quot;] %&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr class=folight&gt; &lt;td&gt;&lt;%=dr[&quot;message&quot;] %&gt; &lt;/td&gt; &lt;/tr&gt; <span class=cmt>&lt;%-- Get all the replies to the Original post and show them --%&gt;</span> &lt;% int no = rs.Tables[&quot;reply&quot;].Rows.Count ; if(no&gt;0) { for(int j=0 ;j&lt;no ; j++) { DataRow rd = rs.Tables[&quot;reply&quot;].Rows[j] ; %&gt; &lt;tr class=fodark&gt; &lt;td align=&quot;center&quot;&gt;&lt;%=&quot;&lt;a href=mailto:&quot;+rd[&quot;email&quot;]+&quot;&gt;&quot;+rd[&quot;name&quot;]+&quot;&lt;/a&gt;&quot; %&gt;&lt;br&gt; &lt;font size=1&gt;&lt;%= DateTime.Parse(rd[&quot;dt&quot;].ToString()).ToShortDateString() %&gt;&lt;br&gt; &lt;%= DateTime.Parse(rd[&quot;dt&quot;].ToString()).ToShortTimeString() %&gt;&lt;/font&gt; &lt;/td&gt; &lt;td&gt;&lt;%=rd[&quot;message&quot;] %&gt; &lt;/td&gt; &lt;/tr&gt; &lt;% } } %&gt; &lt;/table&gt; &lt;/div&gt; &lt;h3 align=&quot;center&quot; class=&quot;fodark&quot;&gt; &lt;a href=forum.aspx&gt;Click Here&lt;/a&gt; to go to back to Forum. &lt;br&gt;Reply to the Above Post.&lt;/h3&gt; &lt;br&gt; &lt;asp:label id=&quot;errmess&quot; text=&quot;&quot; style=&quot;COLOR:#ff0000&quot; runat=&quot;server&quot; /&gt; &lt;form runat=&quot;server&quot;&gt; &lt;table border=&quot;0&quot; width=&quot;80%&quot; align=&quot;center&quot;&gt; &lt;tr &gt; &lt;td class=&quot;fohead&quot; colspan=2&gt;&lt;b&gt;Reply to the Post&lt;/b&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=&quot;folight&quot; &gt; &lt;td&gt;Name :&lt;/td&gt; &lt;td &gt;&lt;asp:textbox text=&quot;&quot; id=&quot;name&quot; runat=&quot;server&quot; /&gt; &lt;asp:RequiredFieldValidator ControlToValidate=name display=static runat=server&gt; *&lt;/asp:RequiredFieldValidator&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt;E-Mail&amp;nbsp;:&lt;/td&gt; &lt;td&gt;&lt;asp:textbox text=&quot;&quot; id=&quot;email&quot; runat=&quot;server&quot;/&gt; &lt;asp:RequiredFieldValidator ControlToValidate=email display=static runat=server&gt; *&lt;/asp:RequiredFieldValidator&gt; &lt;asp:RegularExpressionValidator runat=&quot;server&quot; ControlToValidate=&quot;Email&quot; ValidationExpression=&quot;[\w-]+@([\w-]+\.)+[\w-]+&quot; Display=&quot;Static&quot; Font-Name=&quot;verdana&quot; Font-Size=&quot;10pt&quot; ErrorMesage=&quot;Please enter a valid e-mail address&quot;&gt; &lt;/asp:RegularExpressionValidator&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt; Subject:&lt;/td&gt; &lt;td&gt;&lt;asp:textbox test=&quot;&quot; id=&quot;subject&quot; width=200 runat=&quot;server&quot;/&gt; &lt;asp:RequiredFieldValidator ControlToValidate=subject display=static runat=server&gt; *&lt;/asp:RequiredFieldValidator&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt;Message&amp;nbsp;:&lt;/td&gt; &lt;td&gt; &lt;asp:TextBox id=message runat=&quot;server&quot; Columns=&quot;30&quot; Rows=&quot;15&quot; TextMode=&quot;MultiLine&quot;&gt;&lt;/asp:TextBox&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=folight&gt; &lt;td colspan=2&gt; &lt;asp:Button class=fodark id=write onClick=Submit_Click runat=&quot;server&quot; Text=&quot;Submit&quot;&gt; &lt;/asp:Button&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/table&gt; &lt;/form&gt;&lt;br&gt; &lt;br&gt;&lt;!-- #Include File=&quot;footer.inc&quot; --&gt; &lt;/body&gt;&lt;/html&gt;</pre> </td> </tr> </table> <P>&nbsp;</P> <P>3) <b> postmessage.aspx </b> : The page to save the posted data to the database.<br> <br> Here too, I am presenting the full code in one go! See inline comments for more information. One major change you will find here is that I am using a <i> Parameterized SQL</i> statements to insert a new record into the Database. This is to solve the BUG '<b>Brian R. Bondy</b>' brought to my notice, thanks pal!!<br> <br> The bug is in using normal Insert SQL statements, eg:&nbsp;<br> <i> string sqlString = &quot;INSERT INTO newpost (name, subject) VALUES (' &quot;+name+&quot; ', ' &quot;+subject+&quot; ')&quot;;</i>&nbsp;<br> Where the variables 'name' and 'subject' refer to string's which the user inputs.&nbsp;<br> Say if the user inputs a subject as &quot;This prog's get a prob&quot;, then our sqlString evaluates to&nbsp;<br> <br> <i> &quot;INSERT INTO newpost (name,subject) VALUES ('saurabh' , 'This prog's get a prob')&quot;</i><br> <br> The extra apostrophe<span style="font-size: 10.0pt; mso-fareast-font-family: Times New Roman; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"> ( ' ) in the subject (prog's) will throw a exception since the SQL string becomes a faulty. That's why I have used Parameterized SQL statement which solves this BUG!!<br> <br> Note: One more important BUG (or feature whatever U call it) in OleDb.NET supplied with the .NET SDK beta2 is that than within a Ms Access column of the type 'Memo' you can only input some <b> 4000 characters only</b>! So if your message extends that limit a exception is thrown :(. The only solution is to use <b>ODBC.NET</b>, which can be downloaded from <a href="http://msdn.microsoft.com" target="_blank" class="wbox">msdn.microsoft.com/net</a> separately. ODBC.NET supplies a lot of left out features from OleDb.NET and is a MUST download.</span></P> <P><span style="font-size: 10.0pt; mso-fareast-font-family: Times New Roman; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA">You will also see that below I have made use of the '<b>parsetext</b>' method. This method is used to apply HTML formatting to the Message posted. (If your heart is still beating you can check out <a href="http://www.mastercsharp.com/article.aspx?ArticleID=27&amp;&amp;TopicID=2" class="wbox">this article</a> where I explain in detail the working of this method).</span></P> <table border="0" width="100%" class="code" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <pre>&lt;%@ Page Language=&quot;C#&quot; EnableSessionState=&quot;False&quot; %&gt; &lt;%@ Import Namespace=&quot;System&quot; %&gt; &lt;%@ Import Namespace=&quot;System.Data&quot; %&gt; &lt;%@ Import Namespace=&quot;System.Data.OleDb&quot; %&gt; &lt;%@ Import Namespace=&quot;System.Text&quot; %&gt; &lt;%@ Import Namespace=&quot;System.IO&quot; %&gt; &lt;html&gt; &lt;head&gt; &lt;title&gt;Thank You for Posting !&lt;/title&gt; &lt;script language=&quot;C#&quot; runat=&quot;server&quot; &gt; void Page_Load(Object Src, EventArgs E) { <span class=cmt>//Check id the page is loaded for the first time</span> if (!Page.IsPostBack) { <span class=cmt>//Get the Parameters from the Query string and store it</span> string name = Request.Params[&quot;name&quot;] ; string email = Request.Params[&quot;email&quot;] ; string subject = Request.Params[&quot;subject&quot;] ; string ip = Request.Params[&quot;ip&quot;] ; string date = Request.Params[&quot;date&quot; ]; string message = Request.Params[&quot;message&quot;] ; bool newmess =true ; string previd =&quot;1&quot;; <span class=cmt>//Check of the 'newpost' paramater is 'no' //indicating that its a reply to a previous post</span> if(Request.Params[&quot;newpost&quot;].Equals(&quot;no&quot;)) { newmess =false ; <span class=cmt>//Since its a reply, we get the ID of the topic //to which this post is a reply</span> previd = Request.Params[&quot;previd&quot;] ; } if(newmess) { <span class=cmt>//Execute the code below to insert a new topic</span> string strConn=@&quot;Provider=Microsoft.Jet.OleDb.4.0 ;Data Source=&quot;; strConn+=Server.MapPath(&quot;.\\db\\board.mdb&quot;) ; OleDbConnection myConn = new OleDbConnection(strConn) ; <span class=cmt>//SQL query with Parameters</span> string insertStr =&quot; INSERT INTO newpost (name, email, subject, ip, dt, message) VALUES &quot;; insertStr+=&quot;(@name, @email, @subject, @ip, @dt, @message)&quot;; <span class=cmt>//Create a new OleDbCommand</span> OleDbCommand insertCommand = new OleDbCommand(insertStr, myConn); <span class=cmt>//Add a new Parameter '@name' of the type 'VarChar' //and set its value</span> insertCommand.Parameters.Add(new OleDbParameter(&quot;@name&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@name&quot;].Value = name; insertCommand.Parameters.Add(new OleDbParameter(&quot;@email&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@email&quot;].Value = email; insertCommand.Parameters.Add(new OleDbParameter(&quot;@subject&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@subject&quot;].Value = subject; insertCommand.Parameters.Add(new OleDbParameter(&quot;@ip&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@ip&quot;].Value = ip; insertCommand.Parameters.Add(new OleDbParameter(&quot;@dt&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@dt&quot;].Value = date; insertCommand.Parameters.Add(new OleDbParameter(&quot;@message&quot;, OleDbType.VarChar)); <span class=cmt>//Give a call the the 'parsetext' method to parse the message</span> insertCommand.Parameters[&quot;@message&quot;].Value = parsetext(message); myConn.Open(); <span class=cmt>//Execute Non Query to insert a new topic in the database</span> insertCommand.ExecuteNonQuery(); myConn.Close() ; } else { <span class=cmt>//Insert a reply to a previous topic</span> string strConn=@&quot;Provider=Microsoft.Jet.OleDb.4.0 ;Data Source=&quot;; strConn+=Server.MapPath(&quot;.\\db\\board.mdb&quot;) ; OleDbConnection myConn = new OleDbConnection(strConn); <span class=cmt>//SQL statement with Parameters</span> string insertStr =&quot; INSERT INTO reply (name, email, subject, ip, dt, &quot;; insertStr+=&quot;message, postid) VALUES &quot;; insertStr+=&quot;(@name, @email, @subject, @ip, @dt, @message, @postid)&quot;; <span class=cmt>//Create a new OleDbCommand</span> OleDbCommand insertCommand = new OleDbCommand(insertStr, myConn); <span class=cmt>//Add a new Parameter and set its value</span> insertCommand.Parameters.Add(new OleDbParameter(&quot;@name&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@name&quot;].Value = name; insertCommand.Parameters.Add(new OleDbParameter(&quot;@email&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@email&quot;].Value = email; insertCommand.Parameters.Add(new OleDbParameter(&quot;@subject&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@subject&quot;].Value = subject; insertCommand.Parameters.Add(new OleDbParameter(&quot;@ip&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@ip&quot;].Value = ip; insertCommand.Parameters.Add(new OleDbParameter(&quot;@dt&quot;, OleDbType.VarChar)); insertCommand.Parameters[&quot;@dt&quot;].Value = date; insertCommand.Parameters.Add(new OleDbParameter(&quot;@message&quot;, OleDbType.VarChar)); <span class=cmt>//Give a call the the 'parsetext' method to parse the message</span> insertCommand.Parameters[&quot;@message&quot;].Value = parsetext(message); insertCommand.Parameters.Add(new OleDbParameter(&quot;@postid&quot;, OleDbType.Integer)); insertCommand.Parameters[&quot;@postid&quot;].Value = previd; myConn.Open(); <span class=cmt>//Update the Database</span> insertCommand.ExecuteNonQuery() ; myConn.Close(); <span class=cmt>//SQL string to get the 'replies' column of the topic //to which this post is a reply</span> string replyno = &quot;SELECT replies FROM newpost WHERE postid =&quot;+previd ; insertCommand.CommandText =replyno ; myConn.Open(); OleDbDataReader reader =insertCommand.ExecuteReader() ; reader.Read(); <span class=cmt>//Get the number of replies to this post</span> int rep =reader.GetInt16(0) ; myConn.Close(); rep++ ; <span class=cmt>//SQL statement to update the number of replies //of the topic to which this post is a reply</span> string updtStr =&quot;UPDATE newpost SET replies = &quot;+rep +&quot; WHERE (postid = &quot;+previd+&quot;)&quot; ; insertCommand.CommandText = updtStr; myConn.Open(); <span class=cmt>//Execute the command</span> insertCommand.ExecuteNonQuery(); myConn.Close() ; } <span class=cmt>//Set the text of various textboxes to inform //the user of the text entered into the database</span> NameLabel.Text = name; EmailLabel.Text= email ; SubjectLabel.Text=subject; MessageLabel.Text=message ; } else { errmess.Text=&quot;This Page Cannot be called directly.&quot;; errmess.Text+=&quot; It has to be called from the Form posting page.&lt;br&gt;&quot; ; } } <span class=cmt>//Class to parse the Message into HTML format</span> public string parsetext(string text) { <span class=cmt>//Create a StringBuilder object from the string input //parameter</span> StringBuilder sb = new StringBuilder(text) ; <span class=cmt>//Replace all double white spaces with a single white space //and &amp;nbsp;</span> sb.Replace(&quot; &quot;,&quot; &amp;nbsp;&quot;); <span class=cmt>//Check if HTML tags are not allowed</span> <span class=cmt>//Convert the brackets into HTML equivalents</span> sb.Replace(&quot;&lt;&quot;,&quot;&amp;lt;&quot;) ; sb.Replace(&quot;&gt;&quot;,&quot;&amp;gt;&quot;) ; <span class=cmt>//Convert the double quote</span> sb.Replace(&quot;\&quot;&quot;,&quot;&amp;quot;&quot;); <span class=cmt>//Create a StringReader from the processed string of //the StringBuilder</span> StringReader sr = new StringReader(sb.ToString()); StringWriter sw = new StringWriter(); <span class=cmt>//Loop while next character exists</span> while(sr.Peek()&gt;-1) { <span class=cmt>//Read a line from the string and store it to a temp //variable</span> string temp = sr.ReadLine(); <span class=cmt>//write the string with the HTML break tag //Note here write method writes to a Internal StringBuilder //object created automatically</span> sw.Write(temp+&quot;&lt;br&gt;&quot;) ; } <span class=cmt>//Return the final processed text</span> return sw.GetStringBuilder().ToString(); } &lt;/script&gt; &lt;LINK href=&quot;mystyle.css&quot; type=text/css rel=stylesheet&gt; &lt;/head&gt; &lt;body topmargin=&quot;0&quot; leftmargin=&quot;0&quot; rightmargin=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot;&gt; &lt;!-- #Include File=&quot;header.inc&quot; --&gt; &lt;center&gt; &lt;asp:label id=&quot;errmess&quot; text=&quot;&quot; style=&quot;color:#FF0000&quot; runat=&quot;server&quot; /&gt; &lt;h2 class=&quot;fodark&quot;&gt;&lt;b&gt;Thank You , for posting on the Message Board.&lt;/b&gt;&lt;/h2&gt; &lt;table align=center width=&quot;60%&quot; border=&quot;0&quot; cellspacing=&quot;2&quot; cellpadding=&quot;1&quot; &gt; &lt;tr class=&quot;fohead&quot;&gt;&lt;td colspan=&quot;2&quot;&gt;The information You Posted!&lt;/td&gt;&lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt;Name :&lt;/td&gt; &lt;td&gt;&lt;asp:label id=&quot;NameLabel&quot; text=&quot;&quot; runat=&quot;server&quot; /&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt;E-Mail :&lt;/td&gt; &lt;td&gt;&lt;asp:label id=&quot;EmailLabel&quot; text=&quot;&quot; runat=&quot;server&quot; /&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt;Subject :&lt;/td&gt; &lt;td&gt;&lt;asp:label id=&quot;SubjectLabel&quot; text=&quot;&quot; runat=&quot;server&quot; /&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr class=&quot;folight&quot;&gt; &lt;td&gt;Message :&lt;/td&gt; &lt;td&gt;&lt;asp:label id=&quot;MessageLabel&quot; text=&quot;&quot; runat=&quot;server&quot; /&gt;&lt;/td&gt; &lt;/tr&gt; &lt;/table&gt; &lt;br&gt; &lt;h4 class=&quot;fodark&quot;&gt;&lt;a href=&quot;forum.aspx&quot;&gt;Click here &lt;/a&gt; to go back to the Forum.&lt;br&gt; <span class=cmt>&lt;%-- A little work to show the link to return back to the page if, the post was a reply --%&gt;</span> &lt;% if(Request.Params[&quot;previd&quot;]!=null) { %&gt; &lt;a href='reply.aspx?postid=&lt;%=Request.Params[&quot;previd&quot;] %&gt;'&gt; Click here &lt;/a&gt;to go back where you came from. &lt;% } %&gt; &lt;/h4&gt; &lt;/center&gt; &lt;!-- #Include File=&quot;footer.inc&quot; --&gt; &lt;/body&gt; &lt;/html&gt;</pre> </td> </tr> </table><p><span class=wboxheado>Conclusion</span><br> <b>Congratulations</b>! You have JUST read through a HUGE article. And since you have reached till here, you might as well scroll a bit more and empty your mind below in the feedback form........ Your views will let me know if what I did over 2 days really made sense or was it a waste??<br> Till next time ...&quot; Asta Lavista .... I will be BACK ..... &quot; :)

Comments

Add Comment