There are a system stored procedure sp_who which returns information regarding current sessions on given database.
There is an extended version of this stored procedure is also available.
public static void ProcessError(Exception exception, string otherDetails = "")
{
StackTrace stackTrace = new StackTrace();
string methodName = stackTrace.GetFrame(1).GetMethod().Name;
string className = stackTrace.GetFrame(1).GetMethod().DeclaringType.Name;
string classDetail = string.Format("{0}.{1}", className, methodName);
string exceptionDetail = string.Format("Error occurred in {0}. {1}Message:{2}",
classDetail,
Environment.NewLine,
exception.Message
);
if (!string.IsNullOrWhiteSpace(otherDetails))
{
exceptionDetail = string.Format("{0}{1}Other Details: {2}.",
exceptionDetail,
Environment.NewLine,
otherDetails
);
}
// send this detail for saving
LogError(exceptionDetail);
}
// to get name of calling method
string methodName = stackTrace.GetFrame(1).GetMethod().Name;
// to get name of calling class
string className = stackTrace.GetFrame(1).GetMethod().DeclaringType.Name;
Now lets decide where to save this detail
public enum LogMethods
{
Database,
File,
Email
};
...
...
public static void LogError(string exceptionDetail)
{
switch (errorLogMethod)
{
case LogMethods.Database:
LogErrorInDatabase(exceptionDetail);
break;
case LogMethods.File:
LogErrorInFile(exceptionDetail);
break;
case LogMethods.Email:
SendErrorLog(exceptionDetail);
break;
case default:
SendErrorLog(exceptionDetail);
break;
}
}
Now last step, implement save methods
public static void logErrorMessageInDB(string exceptionDetail, string methodName)
{
try
{
MyDataContext myDC = DataContext;
Log lerror = new Log
{
FullDescription = exceptionDetail,
MethodName = methodName,
CreateDataTime = DateTime.Now
};
iDC.Log.InsertOnSubmit(lerror);
iDC.SubmitChanges();
}
catch (Exception exp)
{
/*
LogErrorInFile(exp);
// OR
LogErrorInEventLog(exp);
*/
}
}
From last few months I am working with InfoPath forms; especially for web hosted
forms. I needed to create a page to host InfoPath form. Here is a quick tutorial
to do this
Assumptions:
We need to do few tasks
So let’s get started.
1. 2. From various options on right side of page, Select “SharePoint Server” (Publish
form to a SharePoint Library). This will open Publishing Wizard dialog.
1. 3. In Publishing Wizard dialog type URL of SharePoint server where you want to
host this InfoPath form and click Next.
1. 5. Select location where you want to publish your InfoPath form; (Please make
sure that SharePoint admin can access this location) and hit Next.
1. 8. After you click on publish it may take few minutes to update screen, Once
published you will see confirmation screen indicating that publication was successful.
Click on Close to finish “Publishing Wizard”
Now Our InfoPath form is ready for publication on SharePoint server. First we need
to upload InfoPath form on server. For that …
2. 1. Open SharePoint website on web browser and select “Site Settings” from Site
Actions menu. (top left side)
2. 2. a) This will open central Administration screen, From left side list, Select
“General Application Settings.”
2. 2. b) When selected (General Application Settings) you will see list of settings
options on right side, Select “Manage Form Template” from InfoPath Forms Services.
(Assuming InfoPath Forms Services is installed and available)
2. 3. You will see list of available InfoPath forms. On top of the page you will
see link for uploading form template
2. 4. From upload page click on browse and select the file we saved in Step 5 of
first section and click Upload
2. 5. Once form is uploaded you will see confirmation message. By clicking OK you
will be redirected to Template management page where you will see your form on list.
2. 6. Select your form and open options menu (when you move your cursor to right
side of forms name you will see dropdown box click there which will open options
menu) and select “Activate to a Site Collection” option.
Now we have InfoPath form available on SharePoint site; we need to make it accessible
to end user for data entry. First of all (assuming we don’t have one) we need to
create a new page to host InfoPath form.
3. 1. To be able to do this open SharePoint website in web browser and select “New
Page” from Site actions menu. (top left)
3. 5. From list of available types select the InfoPath from you want to add and
click on “Add” button. Once done click OK to save your changes.
3. 7. From Categories select “Forms”, From Web Parts select “InfoPath Form web part”
and click “Add”
3. 10. (optional) By default any InfoPath webpart will appear with header, In some
cases you don’t need header, to remove header expand “Appearance” section and select
“None” from Chrome Type. Which will remove header.
3. 11. Once done Click Apply and your page is ready. You can publish it (after any
other formatting related changes you may want to do)
Happy Coding !!! :)
Few days back I needed to join few (Thousand) text file as One file. I thought of
several options
I remembered earlier (dark) days of DOS (Dirty Operation System) when screen was
black and text was white, everything was between 32 rows and 80 columns. Few of
DOS commands were very interesting like | (more) and > or >> (pipe). I thought to
do an experiment with that. I went to DOS prompt in same directory where all .txt
files were stored and used following command
and ...
Yes !!! I got combined file named MergetFile.txt which was 14GB. There are few more
tricks like this
This will join FirstFile.txt, SecondFile.txt, ThirdFile.txt and fifthFile.txt into
MergedFile.txt, this is useful when you want to join files in certain order.
Please note that each file is separated by a space. As you may already know, if
are in different folders please use full path instead of just file name.
This will first join all files with .txt extension and then will join all files
with .csv extension to create a file called MergedFile.txt Here the magic command
is > which takes output of left side command and gives as input to right side command.
If used as >> then output gets be appended. As stated in
the principal of "Occam's razor" "The simplest explanation is
most likely the correct one"
Instead of writing my own code (spending few hours) or download or buy 3rd party
tool (spending money earned in few hours !!!) I used DOS to do the work. Hope this
helps Enjoy coding !!!
This is second article in ’Facelift to Forms’series which describes various options to make beautiful, easy to implement and easy to use web forms. In my previous article ’Facelift to Forms; Part 1: TextBox - By Jay@Thakar.info’ we saw various options to make beautiful Textbox, In this article we will be looking at another element ’Button’.
As you already know Button in web forms represents some action. In many cases web forms were designed very poorly where action items (like buttons) were not visible at all; In this article we will see how we can minimize/eliminate few common mistakes and make your (yes developer’s) and application user’s life easy. This article describes various ways to make beautiful (and highly visible) buttons.
As you may agree, purpose of any web form is to collect information and send it to server. Without button it is difficult to send information to server as Button represents action item on form. There are many things which can be done with Button making it more fun and helping for end user and yet easy to implement. As end result a user will only click on a button if it is visible (to application user).
In this article we will use a simple registration form with 2 buttons ’Register’ and ’Clear’.
/*Code: 1. SimpleForm.htm*/
<input id="register" type="submit" value="Register" />
<input id="clear" type="reset" value="Clear" />Now let’s start giving Facelift to this form.
One of most easy and effective way to change appearance of a Button (or any element) is to use CSS. There are few tricks which you can do with CSS to make Button more beautiful. Let’s see some...
/*Code: 2.CSS_Font.htm*/
<style>
...
...
.loginButton
{
color: #B24F04;
font-family: "Verdana" ,sans-serif;
}
</style>
</head>
...
...
<input id="register" type="submit" value="Register"
class="loginbutton" />
<input id="clear" type="reset" value="Clear"
class="loginButton" />By just applying fonts and changing color now these buttons look slightly better then earlier version. Another exciting thing is to use web fonts
/*Code: 3.Web_Font.htm*/
<style type="text/css">
@font-face
{
font-family: Gentium;
src: url(http://www.princexml.com/fonts/larabie/berylibi.ttf)
format("truetype" );
}
.loginButton
{
color: #B24F04;
font-family: "Gentium" , serif;
}
</style>
...
...
<input id="register" type="submit" value="Register" class="loginButton" />
<input id="clear" type="reset" value="Clear" class="loginButton" />Web fonts rendered on Mozilla Firefox | Web fonts on IE |
As you can see here we are using fonts hosted on server hence it is not required that given fonts should be installed on client’s computer. If browser does not support 'web fonts' then substitute fonts (sans-serif in this case) will be used. This is one of 'cool' thing to do specially when you want to use some funky fonts and you know for sure that given fonts will not be available on client’s computer. Here is result in different browser from above code.
Note: Please be very careful about using this technique as this is still very early stage for this technology, very few browsers supports this, I was able to check this with IE 8 and Firefox 3.5
Now let’s add some borders to these Buttons ...
/*Code: 4.Border.htm*/
<style type="text/css">
...
...
.loginButton
{
color: #B24F04;
font-family: "verdana" ,sans-serif;
border: solid thin #F58F1A;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<input id="register" type="submit" value="Register" class="loginButton" />
<input id="clear" type="reset" value="Clear" class="loginButton" />
</div>Here we just changed appearance of buttons to flat by adding solid border. You can experiment here with various border type and various sides to give various effects. Here is another example of using borders
/*Code: 5.Border_ThickLeft.htm*/
<style type="text/css">
...
...
.loginButton
{
color: #B24F04;
font-family: "Verdana" ,sans-serif;
border: solid 1px #F58F1A;
border-left: 5px solid #F58F1A;
border-right: 5px solid #F58F1A;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<input id="register" type="submit" value="Register" class="loginButton" />
<input id="clear" type="reset" value="Clear" class="loginButton" />
</div>In above 2 examples we added borders, in second example we applied thin (1px) border to all sides of button and we added thick (5px) border on left & right side of Button. This gives nice visual effect which seems bit different the regular button. There are several other styles of border you can play with like outset, double, groove etc.
In most cases we want that disabled Button appear differently. Generally there are two ways to apply different visual style to represent disabled buttons.
/*Code: 6.Disabled_Different.htm*/
<style type="text/css">
...
...
.loginButton
{
color: #B24F04;
font-family: "Verdana" ,sans-serif;
border: solid 1px #F58F1A;
border-left: 5px solid #F58F1A;
border-right: 5px solid #F58F1A;
}
input[disabled]
{
font-family: "Verdana" ,sans-serif;
border: solid 1px gray;
border-left: 5px solid gray;
border-right: 5px solid gray ;
color:gray;
filter: dropshadow(color=#555555,offX=0,offY=1);
filter:alpha(opacity=60); /* IE’s opacity*/
opacity: 0.60;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<input id="register" type="submit" value="Register" disabled="disabled" />
<input id="clear" type="reset" class="loginButton" value="Clear" /></div>Now let’s add some background, Here are few ways we can use background; Let's start with adding solid background...
/*Code: 7.Background_Solid.htm*/
<style type="text/css">
...
...
.loginButton
{
color: black;
font-family: "Verdana" ,sans-serif;
border: solid 1px #F58F1A;
border-left: 5px solid #F58F1A;
border-right: 5px solid #F58F1A;
background-color:#D4E6F7;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<input id="register" type="submit" class="loginButton" value="Register" />
<input id="clear" type="reset" class="loginButton" value="Clear" />
</div>You can also use an image as background, There are two most popular visual effects ...
Let's see example.
/*Code: 8.Background_Image.htm*/
<style type="text/css">
...
...
.loginButton
{
color: black;
font-family: "Verdana" ,sans-serif;
border: solid 1px #F58F1A;
background-image: url("gr.jpg");
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<input id="register" type="submit" class="loginButton" value="Register" />
<input id="clear" type="reset" class="loginButton" value="Clear" />
</div>/*Code: 9.Background_RoundCorner.htm*/
<style type="text/css">
...
...
.loginButton
{
background: transparent url(’RoundCornerBtn.png’) no-repeat scroll top right;
color: white;
height: 38px;
border: none;
width: 130px;
margin: 0px;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<input id="register" type="submit" class="loginButton" value="Register" />
<input id="clear" type="reset" class="loginButton" value="Clear" />
</div>Note:As you may already have seen that we used width: 130px; that is because our image is 130 px wide. The textbox we used here have transparent background do whatever image you use ad background textbox will appear with that image. This style can only be used for fixed width buttons.
After looking at above button a question comes to mind; what if I want to create buttons with dynamic width (i.e. background image gets adjusted based on button’s text). In that case there are several techniques available; Few uses some kind of scripting (i.e. jQuery or JavaScript etc), some uses CSS & HTML combination. We will take a look at one which involves HTML & CSS.
/*Code: 10.RoundCorner_slidedoor.htm*/
<style type="text/css">
...
...
button
{
border: 0;
text-align: center;
padding: 0 12px 0 0;
}
button.submitBtn
{
background: url(bg_button_right.png) right no-repeat;
}
button.submitBtn span
{
height: 24px;
line-height: 24px;
background: url(bg_button_left.png) left no-repeat;
}
button span
{
position: relative;
display: block;
white-space: nowrap;
padding: 0 0 0 12px;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<button id="register" type="submit" class="submitBtn">
<span>Register</span></button>
<button id="clear" type="reset" class="submitBtn">
<span>Clear</span></button>
<button value="submit" class="submitBtn">
<span>Some very logn text</span></button>
</div>Here we used few things; first instead of using inputtag we used button tag we used buttonbecause it allows span tag inside which is not possible input tag. Here CSS for button takes care of left side of rounded corner and span takes care of right side. Here position: relative; in span will make sure that right side gets displayed after end of left side. We kept 12 px of padding on left and right side this is because of rounded curve of image on left and right where we don't want user to type.
Adding icon to an image is always a great move as it adds more visual consistency and more focus from user; as you may already know human brain can process pictures faster than text. Let see various ways to add pictures (icons) to buttons.
/*11.Icon_CSS.htm*/
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<button id="register" type="submit" class="submitBtn">
<span><img src="ico_submit.gif" border="0" alt=""
height="18px" style="vertical-align:middle" /> Register</span></button>
<button id="clear" type="reset" class="submitBtn">
<span><img src="view_refresh.png" border="0"
alt="" height="18px" style="vertical-align:middle" />
Clear</span></button>
</div>In above code we added a span into button and added image into span. Unlike Input here Button tag allows us to add inner span where you can add Image.
Now let’s move to next phase of customization for button, which is behaviors. Just like first section here too we have many different options for customization and add different behaviors.
/*Code: 12.Hover_CSS.htm*/
<style type="text/css">
...
...
button.submitBtn:hover
{
background: url(bg_button_rightH.png) right no-repeat;
}
button.submitBtn:hover span
{
background: url(bg_button_leftH.png) left no-repeat;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<button id="register" type="submit" class="submitBtn">
<span>Register</span></button>
<button id="clear" type="reset" class="submitBtn">
<span>Clear</span></button>
</div>Now this is very neat and apparently easy to implement; and we do not use JavaScript or any programming here :).CSS pseudo-classes are used to add special effects to some selectors. we used hover pseudo-class to add mouse over effect on button. It is possible to get same results using JavaScript.
/*Code: 13.HighlighJS_Hover.htm*/
<style type="text/css">
...
...
.loginButton
{
color: black;
font-family: "Verdana" ,sans-serif;
border: solid 1px #F58F1A;
background-image: url("gr.jpg");
}
.loginButton_Hover
{
font-family: "Verdana" ,sans-serif;
border: solid 1px #F58F1A;
background-image: url("grHover.jpg");
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<input id="register" type="submit" class="loginButton"
value="Register" onmouseout="this.className=’loginButton’;"
onmouseover="this.className=’loginButton_Hover’" />
<input id="clear" type="reset" class="loginButton"
value="Clear" onmouseout="this.className=’loginButton’;"
onmouseover="this.className=’loginButton_Hover’" />
</div>In code above in definition of Input we added JavaScript event handlers for onmouseover and onmouseout where in onmouseover we switch css class to loginButton_Hover and on onmouseout we flipped back to loginButton.
According to one research conducted about page load time and user’s patients concluded that average user can wait approximately ’4 seconds’ for a page to load. Same thing applies to any action done on page like if user clicks on button he/she expects some kind of feedback; you must remember old days of windows forms where upon clicking on button cursor changes to wait (hour glass) cursor. There are various wa ys for web application developer to provide feedback upon user action.
One of popular method to provide feedback is to display message / or animated image indicating an action is initiated. In following example we are displaying a message.
/*14.Feedback_Label.htm*/
<script language="javascript" type="text/javascript">
function displayMessage() {
var divMessage = document.getElementById("div_Message");
divMessage.style.display = ’’;
// following line is to simulate wait in real code you
// may not need to include that;
setTimeout("window.location=’feedback_label.htm’;", 2000);
return true;
}
</script>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
...
...
<input id="register" type="submit" class="loginButton" value="Register"
onmouseout="this.className=’loginButton’;"
onmouseover="this.className=’loginButton_Hover’"
onclick="return displayMessage();" />
<input id="clear" type="reset" class="loginButton" value="Clear"
onmouseout="this.className=’loginButton’;"
onmouseover="this.className=’loginButton_Hover’" />
<div id="div_Message" style="display: none;">
Form Submitter, Please wait ...</div>
</div>| Button before clicking. | Button after clicking; Displays message. |
In above code initially div_Messageis not visible; but on click event of ’Register’ button we call divMessage which displays a message indicating that you have clicked on button and you may need to wait to see result.
Another visual effect you can use is to fade entire form along with displaying message. This is very easy to implement and very effective and entire form changes it’s appearance which is visually more effective technique then just displaying only message.
/*Code: 15.Feedback_dimmer.htm*/
<style type="text/css">
...
...
.opac
{
opacity: 0.4;
filter: alpha(opacity=40);
}
</style>
<script language="javascript" type="text/javascript">
function displayMessage() {
var divM = document.getElementById("div_Message");
divM.style.display = ’’;
var dForm = document.getElementById("div_Form");
dForm.className = "opac"; // apply dimmer effect on entire form
setTimeout("window.location=’15.Feedback_dimmer.htm’;", 2000);
return true;
}
</script>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9"
id="div_Form">
...
...
<input id="register" type="submit" class="loginButton" value="Register"
onmouseout="this.className=’loginButton’;"
onmouseover="this.className=’loginButton_Hover’"
onclick="return displayMessage();" />
<input id="clear" type="reset" class="loginButton" value="Clear"
onmouseout="this.className=’loginButton’;"
onmouseover="this.className=’loginButton_Hover’" />
</div>
<div id="div_Message" style="display: none;">
Form Submitted, Please wait ...</div>Form before button clicked. | Form after button clicked. |
As you can see in above code we used dForm.className = "opac"; to apply fade effect on form. This is very effective visual effect to let user know form processing is initiated and user needs to wait;
However in above 2 methods there is a potential problem; above methods cannot prevent user from clicking on button twice; In some cases we need to prevent user from clicking twice (like sites where you place online order; if user by mistake clicks twice same selection may gets order twice; which is not a good idea); following code prevents double clicks.
/*Code: 16.NoDBLClick.htm*/
<style type="text/css">
...
...
.opac
{
opacity: 0.4;
filter: alpha(opacity=40);
}
</style>
<script language="javascript" type="text/javascript">
function displayMessage() {
var divM = document.getElementById("div_Message");
var bRegister = document.getElementById(’register’);
var dForm = document.getElementById("div_Form");
divM.style.display = ’’;
dForm.className = "opac";
bRegister.form.submit();
bRegister.disabled = 1;
setTimeout("window.location=’16.NoDBLClick.htm’;", 2000);
return true;
}
</script>
...
...
<input id="register" type="submit" class="loginButton"
value="Register"
onmouseout="this.className=’loginButton’;"
onmouseover="this.className=’loginButton_Hover’"
onclick="return displayMessage();" />
<input id="clear" type="reset" class="loginButton"
value="Clear"
onmouseout="this.className=’loginButton’;"
onmouseover="this.className=’loginButton_Hover’" />
</div>
<div id="div_Message" style="display: none;">
Form Submitted, Please wait ...</div>In above case we are first calling bRegister.form.submit();which will execute submit method in this form and then we call bRegister.disabled = 1;which will disable ’Register’ button which will prevent user from clicking it again.
Initial Submmision on September 24, 2009.
As developer if you start thinking about this question "How can I make End User’s life easy?" and implement changes You will make your life easy; In the end it is NOT you who decides how good your application is; it is Application’s Users. Happy Coding :)
If you have any questions, please feel free to contact me at: Jay@Thakar.info
In this article I am presenting a different way to look at EditItemTemplate, using which user navigation for editing is reduced and … it looks very different (see screeen shots) then regular implementation of GridView.
Few days back I got an assignment, I needed to add few new fields in a DataViewand let user edit those (along with all existing fields).
I thought it was a very small change, just new fields in ItemTemplate and EditItemTemplateand perform few basic validations on it using JavaScript and I m done !. I was dead wrong. As soon as I modified EditItemTemplate, a Horizontal scrollbar started to appear on page. One of UI rule in our entire application on minimum resolution 1024x678 and with default font size, no Horizontal Scrollbar should appear on any of page.So I started thinking and creating new concepts. Here we had few options.
Option 1:
Create new page for edit. When user clicks on edit button we redirect user to new page and when user clicks on Update/Close we bring them back on list page.
Problem:It was lengthy process to create new page, validate and bring them back, Also in this case link between current work and edit was broken as user was moving back and forth for editing.
Option 2:
Create a popup window, when user clicks on edit button we create a popup window and let user edit in new window, when user clicks on update/close user comes back to list page.
Problem:
As modern design approach we were moving away from popup windows (which opens as new window) and tried to find some other alternate for this popup windows. While talking about this option I also threw AjaxControlToolkit Model Popup but it had same problem as option 1, link between current data and editing data was broken.
Option 3:
Create inline form which gets displayed between 2 rows in GridView, Let user make any modification required there and when user clicks on update/close bring back same row. This is not new technique but there are many companies who offer this kind of facility (and change big bucks for that) As this was bit easy to implement I thought let’s try creating it on our own (and save some buck, of course for company :) )
Problem: NONE !!!
My IT Director was very happy to see this prototype, She suggested that I should implement this style. And the journey begins …
There are few things which generates this facility.
As you already know GridView gets rendered as table and each column defination in GridViewgenerates one column; so we defined only one column. To create an illusion of Table we defined only one column and created a table in it; We created required columns in this new inner table. This gets rendered as one table per DataRow with all columns we specified.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="4"
ForeColor="#333333" GridLines="Both" Width="60%" OnRowEditing="GridView1_RowEditing">
<RowStyle BackColor="#EFF3FB" />
<Columns>
<asp:TemplateField>
...
...
<ItemTemplate>
<table width="100%" cellpadding="0" cellspacing="0" >
<tr>
<td style="width:15%;" align="left">
<%#DataBinder.Eval(Container.DataItem, "FirstName")%>
</td>
<td style="width:15%;" align="left">
<%#DataBinder.Eval(Container.DataItem, "LastName")%>
</td>
<td style="width:35%;" align="left">
<%#DataBinder.Eval(Container.DataItem, "Web")%>
</td>
<td style="width:35%;" align="left">
<%#DataBinder.Eval(Container.DataItem, "Email")%>
</td>
</tr>
</table>
</ItemTemplate>Above ItemTemplate will generate one table per row. Now let's see how we can make inline editing possible.
<EditItemTemplate>
<center>
<ajx:RoundedCornersExtender ID="rce" runat="server" TargetControlID="pnlHead"
Radius="6" Corners="Top" BorderColor="black" />
<asp:Panel ID="pnlHead" runat="server" Font-Bold="true" ForeColor="white"
BackColor="#507CD1"
Width="50%">
<center>
<table>
<tr>
<td>
Updating
<%#DataBinder.Eval(Container.DataItem, "FirstName")%>,
<%#DataBinder.Eval(Container.DataItem, "LastName")%>
</td>
</tr>
</table>
</center>
</asp:Panel>
<ajx:RoundedCornersExtender ID="rceDetail" runat="server" TargetControlID="pnlDetail"
Radius="6" Corners="Bottom" BorderColor="black" />
<asp:Panel ID="pnlDetail" runat="server" Width="50%">
<table width="100%">
<tr>
<td align="right" style="width: 30%">
First Name:
</td>
<td style="padding-right:10px;">
<asp:TextBox ID="tbFirstName" Width="100%" runat="server"
Text='<%#DataBinder.Eval(Container.DataItem, "FirstName")%>'>
</asp:TextBox>
</td>
</tr>
<tr>
<td align="right">
Last Name:
</td>
<td style="padding-right:10px;">
<asp:TextBox ID="TextBox1" runat="server" Width="100%"
Text='<%#DataBinder.Eval(Container.DataItem, "LastName")%>'>
</asp:TextBox>
</td>
</tr>
<tr>
<td align="right">
Web:
</td>
<td style="padding-right:10px;">
<asp:TextBox ID="TextBox2" runat="server" Width="100%"
Text='<%#DataBinder.Eval(Container.DataItem, "Web")%>'>
</asp:TextBox>
</td>
</tr>
<tr>
<td align="right">
eMail:
</td>
<td style="padding-right:10px;">
<asp:TextBox ID="TextBox3" runat="server" Width="100%"
Text='<%#DataBinder.Eval(Container.DataItem, "eMail")%>'>
</asp:TextBox>
</td>
</tr>
</table>
<div style="padding-top: 3px; border-top: thin solid black;" id="divUpdate">
<asp:Button CssClass="btnNormal" runat="server" ID="bUpdate"
Text="Update" OnClick="bUpdate_Click" />
<asp:Button OnClick="bCancel_Click" CssClass="btnNormal"
runat="server" ID="bCancel" Text="Cancel" />
</div>
</asp:Panel>
</center>
</EditItemTemplate>
</asp:TemplateField>From our ItemTemplate it was clear that in edit mode we will get only one column, so just like in ItemTemplate here too we defined edit layout whichever way we want. In our case we wanted rounded corner center aligned table, with different style on header, to acheave this we used AjaxControlToolkit's RoundedCornerExtension, it has facility to define which corners we want as rounded corners so as header we defined only top corners as rounded and for content part we defined only bottom corners as rounded corners. And using table we defined a layout of form for editing. this gives us a nice looking form when user clicks on edit button. And as result we got following GridView.
As final touch we also needed header to match given columns so we used same type of style we used on ItemTemplate.
<HeaderTemplate>
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td style="width:15%;" align="left">
First Name
</td>
<td style="width:15%;" align="left">
Last Name
</td >
<td style="width:35%;" align="left">
Web
</td>
<td style="width:35%;" align="left">
Email
</td>
</tr>
</table>
</HeaderTemplate>Note:Please make sure that ItemTemplate table defination matches to header (specially width of each column) as it will give one table look.
Update:After publishing this article I got several requests about few things ...
So here is code ...
Main purpose for this article was to present different way to use ItemTemplate; I understand taht there may be few questions about updating data which is beyond of scope of this article. Here is sample code for how to access updated value when user clicks on Update Button.
protected void bUpdate_Click(object sender, EventArgs e)
{
TextBox tbF = (TextBox)GridView1.Rows[GridView1.EditIndex].FindControl("tbFirstName");
TextBox tbL = (TextBox)GridView1.Rows[GridView1.EditIndex].FindControl("tbLastName");
TextBox tbW = (TextBox)GridView1.Rows[GridView1.EditIndex].FindControl("tbWeb");
TextBox tbE = (TextBox)GridView1.Rows[GridView1.EditIndex].FindControl("tbEmail");
// now you have all values entered by user
// set those values in dataset and update
// OR generate UPDATE sql statement here and save values in db.
// more details / example can be found at
// http://msdn.microsoft.com/en-us/library/ms972948.aspx
// OR
// http://www.aspdotnetcodes.com/GridView_Insert_Edit_Update_Delete.aspx
refreshData();
}
private void refreshData()
{
GridView1.EditIndex = -1;
ViewState["EditRowID"] = null;
GridView1.DataSource = CreateTable();
GridView1.DataBind();
}The trick here is to use FindControl on currently editing row and pass ID of control which you want to access. And to accesss currently editing row you can use GridView1.Rows[GridView1.EditIndex]. Once we are done updating data change EditIndex to -1 (indicating no row is in edit state); this will restore all rows of grid back to view state (i.e. hide edit template).
For more details on how to update data into database please refer to following link.
http://msdn.microsoft.com/en-us/library/ms972948.aspx
private int iCurrentEdit = -1;
protected void GridView1_RowEditing(Object sender, GridViewEditEventArgs e)
{
GridView1.EditIndex = e.NewEditIndex;
GridView1.DataSource = CreateTable();
GridView1.DataBind();
ViewState.Add("editRowIndex", e.NewEditIndex);
ImageButton editButton;
foreach (GridViewRow row in GridView1.Rows)
{
if (row.RowIndex != e.NewEditIndex)
{
editButton = (ImageButton)(row.Cells[1].Controls[0]);
editButton.ImageUrl = "./edit_off.gif";
editButton.Enabled = false;
}
else
{
ViewState.Add("EditRowID", row.DataItemIndex.ToString());
if (ViewState["fname"] != null)
// indicates we have values from previous editing session which are not saved
{
// get elements from edit template
TextBox tbF = (TextBox)row.FindControl("tbFirstName");
TextBox tbL = (TextBox)row.FindControl("tbLastName");
TextBox tbW = (TextBox)row.FindControl("tbWeb");
TextBox tbE = (TextBox)row.FindControl("tbEmail");
// restore previous values
tbF.Text = ViewState["fname"].ToString();
tbL.Text = ViewState["lname"].ToString();
tbW.Text = ViewState["web"].ToString();
tbE.Text = ViewState["email"].ToString();
}
}
}
}
protected void GridView1_PageIndexChanging(Object objDGName, GridViewPageEventArgs e)
{
GridView1.DataSource = CreateTable();
GridView1.PageIndex = e.NewPageIndex;
GridView1.EditIndex = -1;
GridView1.DataBind();
if (iCurrentEdit != -1)
{
GridView1_RowEditing(GridView1, new GridViewEditEventArgs(iCurrentEdit));
}
}
protected void GridView1_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow ||
e.Row.RowType == DataControlRowType.EmptyDataRow)
{
int iEditRowID = int.Parse((ViewState["EditRowID"] == null ? "-2" :
ViewState["EditRowID"].ToString()));
if (iEditRowID != -2 && e.Row.DataItemIndex == iEditRowID)
{
iCurrentEdit = e.Row.RowIndex;
}
else if (iEditRowID != -2)
{
ImageButton editButton;
editButton = (ImageButton)(e.Row.Cells[1].Controls[0]);
editButton.ImageUrl = "./edit_off.gif";
editButton.Enabled = false;
}
}
}There are few things here ...
We defined a class level variable called iCurrentEdit with initial value of -1 indicating no row is in edit state.
When user clicks on Edit (protected void GridView1_RowEditing(Object sender, GridViewEditEventArgs e)) button we loop thrue entire grid to find DataItemIndex and when we find it we store DataItemIndex into ViewState using ViewState.Add("EditRowID", row.DataItemIndex.ToString());
Now when user clicks to change page (protected void GridView1_PageIndexChanging(Object objDGName, GridViewPageEventArgs e)) first we call GridView1.DataBind(); which will call RowDataBound for each row.
Finally in RowDataBound event (protected void GridView1_RowDataBound(Object sender, GridViewRowEventArgs e)) we retrive value of currently editing DataItemIndex (int iEditRowID = int.Parse((ViewState["EditRowID"] == null ? "-2" : ViewState["EditRowID"].ToString()));) and then we compare this value against current row's DataItemIndex, If it is same then this indicates this is row in edit state hence we store RowIndex into iCurrentEdit so; when if (iCurrentEdit != -1) gets executed in PageIndexChanging there will be value in iCurrentEdit (if a row is in edit state) if this is the case then we call GridView1_RowEditing(GridView1, new GridViewEditEventArgs(iCurrentEdit)); to simulate rowEditClick.
In above code there is one potential problem, If user clicks on edit and changes First Name (or any other field in that matter); does not click on update button and goes to other page to view some information and comes back, above code will take care of putting correct row in edit mode but will not preserve values entered by user. To save those values temperarly we can use ViewState.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GridView1.DataSource = CreateTable();
GridView1.DataBind();
}
else
{
if (ViewState["editRowIndex"] != null)
// indicates we have values from edit which needs to be saved in viewstate
{
int iEditRowID = int.Parse((ViewState["editRowIndex"] == null ? "-2" :
ViewState["editRowIndex"].ToString())); // get current edit row index
// get all elements from edit template
TextBox tbF = (TextBox)GridView1.Rows[iEditRowID].FindControl("tbFirstName");
TextBox tbL = (TextBox)GridView1.Rows[iEditRowID].FindControl("tbLastName");
TextBox tbW = (TextBox)GridView1.Rows[iEditRowID].FindControl("tbWeb");
TextBox tbE = (TextBox)GridView1.Rows[iEditRowID].FindControl("tbEmail");
// save all values into viewstate for future use
if (tbF != null)
{
ViewState.Add("fname", tbF.Text);
ViewState.Add("lname", tbL.Text);
ViewState.Add("web", tbW.Text);
ViewState.Add("email", tbE.Text);
}
}
}
}
private void refreshData()
{
GridView1.EditIndex = -1;
ViewState["EditRowID"] = null;
GridView1.DataSource = CreateTable();
GridView1.DataBind();
// clear viewstate (this is called from UpdateButtonClicked and CancelButtonClicked
ViewState["fname"] = null;
ViewState["lname"] = null;
ViewState["web"] = null;
ViewState["email"] = null;
ViewState["editRowIndex"] = null;
}When user clicks on edit button for any row; user can not (or should not) be able to click on edit button of any other row; for that we need to disable all edit buttons when user is in edit mode.
protected void GridView1_RowEditing(Object sender, GridViewEditEventArgs e)
{
...
...
ImageButton editButton;
foreach (GridViewRow row in GridView1.Rows)
{
if (row.RowIndex != e.NewEditIndex)
{
editButton = (ImageButton)(row.Cells[1].Controls[0]);
editButton.ImageUrl = "./edit_off.gif";
editButton.Enabled = false;
}
}
...
...
}
protected void GridView1_RowDataBound(Object sender, GridViewRowEventArgs e)
{
...
...
else if (iEditRowID != -2)
{
ImageButton editButton;
editButton = (ImageButton)(e.Row.Cells[1].Controls[0]);
editButton.ImageUrl = "./edit_off.gif";
editButton.Enabled = false;
}
}Here when user clicks on Edit button we loop through entire grid and Disable edit button if it's index does not match with current edit row index. To access edit button we use editButton = (ImageButton)(e.Row.Cells[1].Controls[0]); as you already know we have created entire edit template in one table cell hence second cell (at cell index 1) will be for edit/update/cancel buttons and from that we access first control which is edit button; we disable it and change image icon to indicate this row is not available for editing. Almost similer thing we are doing on row bound which takes care of rows which are not on current page. When user goes from currently editing page to another page we wanted to disable editing which we took care in RowBound event.
Updated Code for various event on Sep 23, 2009.
Initial submission on Sep 14, 2009.
I hope this help you to create easy to use GridView
Happy Coding :)