Thursday, September 24, 2009

Facelift to Forms; Part 2: Button - By Jay@Thakar.info


Introduction

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’.

Background

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.

Button

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" />
Simple Form
Simple form without any CSS

Now let’s start giving Facelift to this form.

Magic of CSS

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" />
Added some fonts
Form with Fonts

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 on Firefox
Web fonts rendered on Mozilla Firefox
Web fonts on IE
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>
Simple Borders
Buttons with Border

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>
Border with thick left border

 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.

Different visual effect based on state

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>
Disabled textbox
Different Disabled formatting.

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>
Solid color as background
Button with solid background.

You can also use an image as background, There are two most popular visual effects ...

  1. Gradient effect
  2. Rounded corners

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>
Gradient Background
/*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>
Button with Rounded Corner
Button with Rounded Corner

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.

Slide Door Technique for Rounded Corners

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>
Rounded corners with sliding door style.
Rounded corners with sliding door style

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.

Button with Icon

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>
Button with Icon
Button with Icon

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.

Behavior

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.

Hover

/*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>
Highlight on Focus

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>
Highlight on Focus with JavaScript

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.

Providing Feedback about Action taken

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.

Displaying Message

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.
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.

Fade effect on form

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 before button clicked.
Form after 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;

Preventing Accidents (Double Clicks)

 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>
Disabled button after click.
Disabled button after click.

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.

History

Initial Submmision on September 24, 2009.

Summary

Download Source  Download Source

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

Saturday, September 12, 2009

Inplace Edit in GridView By Jay@Thakar.info

Introduction

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.

Inline Edit

Background

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.

Download Source   Download Source

Various 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.


Image 2: Edit View in inline Grid View

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 ...

  1. Code to update data on click of Update button.
  2. Add paging and code to preserve edit while moving between pages in pageble GridView.
  3. Disable all Edit button in Edit state (so user can not 'by accident' update other row.

So here is code ...

1.Code to update data on click of Update button.

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

2. Add paging and code to preserve edit while moving between pages in pageble GridView.


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;

}

3. Disable all Edit button in Edit state (so user can not 'by accident' update other row.

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.

History

Updated Code for various event on Sep 23, 2009.

Initial submission on Sep 14, 2009.

Download Source   Download Source

Summary

I hope this help you to create easy to use GridView

Happy Coding :)

Wednesday, September 2, 2009

Facelift to Forms; Part 1: TextBox - By Jay@Thakar.info

Introduction

This is first article in 'Facelift to Forms' series which describes various options to make beautiful, easy to implement and easy to use web forms. In each article I will be describing one element of web forms and various ways to give 'Facelift' to web forms.

Download Download source

Background

One of our new client mentioned that they were not happy with their website's performance. They had very good ad campaign and good continuous flow of new visitors but they were not registering. I thought let's take a look at registration form as 'End User'; I went to their site and clicked on "Register" link. If I see that registration form as 'End user' I see an ugly form with many form elements put together without putting much thought.

As you agree that web forms is one of very widely used way to collect information from any web application. In many cases it may be the only way to save information and yet it is not used correctly in many cases.  I saw some of web forms were just replacement of multipage printed copy of forms asking for same information again and again. It is vital for any web application developer to understand usage of various elements in web forms and know verious options to make 'End User's life easy. If implemented correctly customers will love you and if not then customers will hate you.

TextBox

Any web form is incomplete without a textbox. You can do many things with textbox to make it more fun and helping for end user. Here are few ways to do this.
  1. Add some Spice (CSS)
  2. Shine (Highlight) on focus
  3. Have some Watermark (Javascript/AjaxControl Toolkit)
  4. Use of Theme & CSS to make your (yes developer's) life easy

In this example we will use a simple registration form with 2 fields, name & email address.

/*Code: SimpleForm.htm*/
<div style="border: solid thin black; padding: 10px;">
Name: <input id="tdName"> <br /> <br />
Email : <input id="tbSimmple"> <br /> <br />
<input id="register" type="submit" value="Register">
</div>
Simple Form
Image 1: Simple form without any CSS

Now let's start giving facelift to this form.

1. Add some Spice (CSS)

One of most easy and effective way to change appearance of a textbox (or any element)is to use CSS. There are few tricks which you can do with CSS to make TextBox more beautiful. Let's see some...


/*Code:CSS_Font.htm*/
<style>
/* Apply default fonts*/
<style>
.loginBox
{
width: 80%;
color: #B24F04;
font-family: "Verdana" ,sans-serif;
}
.loginText
{
color:#FF8326;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px;background-color:#FDEDD9">
<span class="loginText">Name:</span>
<input id="login" class="loginBox" /><br />
<br />
<span class="loginText">Email :</span>
<input id="email" class="loginBox" /><br />
<br />
<input id="Submit1" type="submit" value="Register" />
</div>
Added some fonts
Image 2: Form with Fonts

By just applying fonts and make consistence width to both textboxes makes thsi form look bit better.

/*Web_Font.htm*/
<style type="text/css">
@font-face
{
font-family: Gentium;src: url(http://www.princexml.com/fonts/larabie/berylibi.ttf)
format("truetype");

}

.loginURL
{
width: 80%;
color: Gray;
font-family:"Gentium" , serif;
}
</style>
<div style="border: solid thin black; padding: 10px;">
Name: <input id="Text1" class="loginURL" /><br /> <br />
Email: <input id="Text2" class="loginURL" /><br /> <br />
<input id="Submit2" type="submit" value="Register" />
</div>

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.

Web fonts on Firefox
Web fonts rendered on Mozilla Firefox
Web fonts on IE
Web fonts on IE

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 this TextBox ...

/*Border.htm*/
<style type="text/css">
.loginText
{
color: #FF8326;
}
.loginBorders
{
width: 80%;
color: #B24F04;
font-family: serif;
border: solid thin #F58F1A;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input id="Text3" class="loginBorders" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text4" class="loginBorders" /><br />
<br />
<input id="Submit3" type="submit" value="Register" />
</div>
Simple Borders
Textbox with Border

Above code generates following form. Here we changed appearance of TextBox to flat with solid border. You can experiment here with various border type and various sides to give various effects. Here is another example of using borders

<style type="text/css">
.loginText
{
color: #FF8326;
}
.loginBorders
{
width: 80%;
color: #B24F04;
font-family: serif;
border: solid 1px #F58F1A;
border-left: 7px solid #F58F1A;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input id="Text3" class="loginBorders" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text4" class="loginBorders" /><br />
<br />
<input id="Submit3" type="submit" value="Register" />
</div>
Border with thick left border
Regular border on 3 sides and thick border on left side.

In above 2 examples we added borders, in second example we applied thin (1px) border to all sides of textbox and we added thick (7px) border on left side of textbox. This gives nice visual effect which seems bit different the regular textbox. Now in next example let's add drop shadow to borders.

/*Border_Shadow.htm*/
<style type="text/css">
.loginText
{
color: #FF8326;
}
.loginBordersShadow
{
width: 80%;
color: #B24F04;
font-family: serif;
border: outset thin #F58F1A;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input id="Text5" class="loginBordersShadow" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text6" class="loginBordersShadow" /><br />
<br />
<input id="Submit4" type="submit" value="Register" />
</div>
Drop Shadow to TextBox
Textbox borders with shadow.

In most cases we want that disabled TextBox appear differently. Generally there are two ways, either use different visual style to represent disabled textbox or let TextBox appear as Label.

/*Disabled_Different.htm*/
<style type="text/css">
.loginText
{
color: #FF8326;
}
.loginBorders
{
width: 80%;
color: #B24F04;
font-family: serif;
border: solid thin #F58F1A;
}
input[disabled]
{
width: 80%;
color: #333333;
background-color:#eeeeee;
font-family: serif;
border: solid 1px #F58F1A;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input id="Text5" disabled="disabled" value="Jay" style="width:80%" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text6" class="loginBorders" /><br />
<br />
<input id="Submit4" type="submit" value="Register" />
</div>
Disabled textbox
Different Disabled formatting
code>/*Disabled_Label.htm*/
<style type="text/css">
.loginText
{
color: #FF8326;
}
.loginBorders
{
width: 80%;
color: #B24F04;
font-family: serif;
border: solid thin #F58F1A;
}
input[disabled]
{
width: 80%;
color: #333333;
background-color:Transparent;
font-family: serif;
border: hidden 1px #F58F1A;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input id="Text5" disabled="disabled" value="Jay" style="width:80%" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text6" class="loginBorders" /><br />
<br />
<input id="Submit4" type="submit" value="Register" />
</div>
Disabled textbox as label
Disabled textbox as Label.

Now let's add some background, Here are few ways we can use background...

/*Background_Solid.htm*/
<style type="text/css">
.loginText
{
color: #FF8326;
}
.loginBg
{
width: 80%;
color: #B24F04;
font-family: serif;
border: solid thin #F58F1A;
background-color: #FFFFB8;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input id="Text5" class="loginBg" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text6" class="loginBg" /><br />
<br />
<input id="Submit4" type="submit" value="Register" />
</div>
Solid color as background
Textbox with solid background.

You can also use an image as background, There are two most popular visual effects 1) Gredient effect and 2) rounded corners. Lets see example.

/*Background_Image.htm*/
<style type="text/css">
.loginText
{
color: #FF8326;
}
.loginBg
{
width: 80%;
color: #B24F04;
font-family: serif;
border: solid thin #F58F1A;
background-image:url("gr.jpg");
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input id="Text5" class="loginBg" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text6" class="loginBg" /><br />
<br />
<input id="Submit4" type="submit" value="Register" />
</div>

Gradient Background
<style type="text/css">
.loginText
{
color: #FF8326;
}
.loginBg
{
width: 300px;
color: #B24F04;
font-family: serif;
background-color:Transparent;
background-image:url("rounded.png");
background-repeat:no-repeat;
border-style:hidden;
padding-left:5px;

}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input id="Text5" class="loginBg" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text6" class="loginBg" /><br />
<br />
<input id="Submit4" type="submit" value="Register" />
</div>
Textbox with Rounded Corner
Textbox with Rounded Corner

Note: As you may already have seen that we used width: 300px; that is because our image is 300 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 textboxes. (There are few ways get this effect with dynamic width but it involves Few Divs it is not only with one Textbox.

2. Shine (Highlight) on focus

p>As 'End user' I am too distracted, While filling a form I may lose my focus; (answer a phone, go on a brake etc.) when I come back I may need to 'think' where was I?; One of the technique which we (as developer) can use to draw attention of user is change visual appearance of element which has focus and change back to original state when it loses the focus. Microsoft is using this technique from early days of windows. There are many different ways to highlight (apply different CSS) on focus of TextBox.

/*Focus_Highlight.htm*/
<style type="text/css">
input[type=text]:focus
{
border: 1px solid black;
background-image: url( "gr.jpg" );
color: #B24F04;
font-family: serif;
width: 80%;
}
input[type=text]
{
border: 2px solid #FF8326;
background-image: url( "gr.jpg" );
width: 80%;
color: #B24F04;
font-family: serif;
}
.loginText
{
color: #FF8326;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input type="text" id="Text15" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text16" type="text" /><br />
<br />
<input id="Submit9" type="submit" value="Register">
</div>
Highlight on Focus

Now this is very neat and apparently easy to implement. One of the thing here is above CSS will only apply to elements with type=text and all other elements will be untouched; and we do not use JavaScript or any programming here :) This may not be supported by all browsers (specially old browsers) in this case JavaScript can save the day...

/*FocusJS_Highlight.htm*/
<style type="text/css">
.loginHighlight
{
border: 1px solid black;
background-image: url( "gr.jpg" );
color: #B24F04;
font-family: serif;
width: 80%;
}
.loginNormal
{
border: 2px solid #FF8326;
background-image: url( "gr.jpg" );
width: 80%;
color: #B24F04;
font-family: serif;
}
.loginText
{
color: #FF8326;
}
</style>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input type="text" id="Text15" onblur="this.className='loginNormal';"
class="loginNormal" onfocus="this.className='loginHighlight'" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text16" type="text" onblur="this.className='loginNormal';"
class="loginNormal" onfocus="this.className='loginHighlight'" /><br />
<br />
<input id="Submit9" type="submit" value="Register" />
</div>
Highlight on Focus with JavaScript

3. Have some Water (mark)

Now let's move to next level in customization. We can add watermark effect here, This is very useful feature for providing some help to user while filling a form. You can put some message in text box which will be displayed when text box is empty when user types something help message disappears. There are few ways to do this...

/*Watermark_JS.htm*/
<style type="text/css">
.loginHighlight
{
border: 1px solid black;
background-image: url("gr.jpg" );
color: #B24F04;
font-family: serif;
width: 80%;
}
.loginNormal
{
border: 2px solid #FF8326;
background-image: url("gr.jpg" );
width: 80%;
color: #B24F04;
font-family: serif;
opacity: 0.6;
filter: alpha(opacity=60);

}
.loginText
{
color: #FF8326;
}
</style>
<script language="javascript" type="text/javascript">
function textOnFocus(textBox)
{
textBox.className='loginHighlight';
if(textBox.value==textBox.defaultValue)
{textBox.value='';}
}
function textOnBlur(textBox)
{
textBox.className='loginNormal';
if(textBox.value=='')
{textBox.value=textBox.defaultValue;}
}
</script>
<div style="border: solid thin #FF4A00; padding: 10px; background-color: #FDEDD9">
<span class="loginText">Name:</span>
<input type="text" id="Text15" onblur="textOnBlur(this)"
value="Click here to enter Login Name"
class="loginNormal"
onfocus="textOnFocus(this);" /><br />
<br />
<span class="loginText">Email:</span>
<input id="Text16" type="text" onblur="textOnBlur(this)"
value="Click here to enter Email"
class="loginNormal"
onfocus="textOnFocus(this);" /><br />
<br />
<input id="Submit9" type="submit" value="Register" />
</div>
TextBox before typing information.
TextBox before typing information.
TextBox after typing information.
TextBox before typing information.

Here we are taking advantage Default Value using JavaScript. When you define value as part of element specification it becomes 'Default Value', and using multiple CSS classes based on value. When user have not entered anything we wanted to apply transparency of 60% but as soon as user enters information we wanted to remove transparency hence we are applying different css based on value in text box. If user have not entered anything in text box then value and 'DefaultValue' will be same in that case we apply different css classtextBox.className='loginNormal'; and if user have entered any value then we apply different CSS.

One of other way to apply watermark effect is to use WaterMark extender from AjaxControlToolkit.

/*Default.aspx*/
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajxTK" %>
...
...
...
<style type="text/css">
.loginHighlight
{
border: 1px solid black;
background-image: url("gr.jpg" );
color: #B24F04;
font-family: serif;
width: 80%;
}
.loginNormal
{
border: 2px solid #FF8326;
background-image: url("gr.jpg" );
width: 80%;
color: #B24F04;
font-family: serif;
opacity: 0.6;
filter: alpha(opacity=60);
}
.loginText
{
color: #FF8326;
}
</style>
<div style="border: solid thin black; padding: 10px;">
<span class="frmLbl">Name:</span>
<asp:ScriptManager ID="sm" runat="server">
</asp:ScriptManager>
<ajxTK:TextBoxWatermarkExtender ID="tbWMEX_ProcName" runat="server"
TargetControlID="tbLoginName"
WatermarkCssClass="loginNormal" WatermarkText="Click here to enter Name.">
</ajxTK:TextBoxWatermarkExtender>

<asp:TextBox id="tbLoginName" cssclass="loginHighlight" runat="server" /><br />
<br />
<span class="frmLbl">Email:</span>
<ajxTK:TextBoxWatermarkExtender ID="TextBoxWatermarkExtender1" runat="server"
TargetControlID="tbEmail"
WatermarkCssClass="loginNormal" WatermarkText="Click here to enter Email.">
</ajxTK:TextBoxWatermarkExtender>


<asp:TextBox id="tbEmail" runat="server" class="loginHighlight" /><br />
<br />
<input id="Submit10" type="submit" value="Register">
</div>
TextBox before typing information.
TextBox before typing information.
TextBox after typing information.
TextBox after typing information.

As you can see it is fairly simple to add watermark effect using TextBoxWaterMark Extender from AjaxControlToolkit. Main properties to define here are

  1. TargetControlID This indicates id of control on which we need to display watermark effect.
  2. WatermarkCssClassThis indicates name of CSS to used as watermark display
  3. WatermarkText This indicates text to be displayed as watermark.

4. Use of Theme & CSS to make your (yes developer's) life easy

These techniques you saw was fairly easy to implement; yes it is when we have few textboxes, but imagine that you have to do this for each textbox on your web application (usually which contains hundreds of textboxes). We can use combination of Themes and CSS to apply most of visual appearances and behavior. Here I am assuming that you are aware of themes as this article is not intended to describe how to use themes.

/*Default.Skin*/
<asp:TextBox onblur="textOnBlur(this);" CSSclass="loginNormal"
onfocus="textOnFocus(this);" runat="server"></asp:TextBox>

/*JavaScript*/
<script language="javascript" type="text/javascript">
function textOnFocus(textBox)
{
textBox.className='loginHighlight';
if(textBox.value==textBox.defaultValue)
{textBox.value='';}
}
function textOnBlur(textBox)
{
if(textBox.value=='')
{textBox.value=textBox.defaultValue;
textBox.className='loginNormal opac';
}
else
{
textBox.className='loginNormal';
}
}
</script>

You can attach this Script in separate file or you can use master page which attaches javascript file.
By doing this each page which uses this master page will automatically get
script and you (yes developers) do not need to write redundant code.


/*Aspx page*/
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="easyTheme.aspx.vb"
Inherits="FaceliftToForms_TextBox.easyTheme" Theme="Default" %>
...
...
<style type="text/css">
.loginHighlight
{
border: 2px solid grey;
background: #FFFFFF url( "gr.gif" ) repeat-x 0 1px;
color: #666666;
width: 80%;
}
.loginNormal
{
border: 1px solid #cdcdcd;
background: #FFFFFF url( "gr.gif" ) repeat-x 0 1px;
color: #666666;
width: 80%;
opacity:0.6;
filter:alpha(opacity=60);
}
.frmLbl
{
font-family: serif;
}
</style>
<div style="border: solid thin black; padding: 10px;">
<span class="frmLbl">Name:</span>
<asp:ScriptManager ID="sm" runat="server">
</asp:ScriptManager>
<asp:TextBox id="tbLoginName" cssclass="loginNormal" runat="server"
Text="Click here to enter Login Name."/><br />
<br />
<span class="frmLbl">Email:</span>
<asp:TextBox id="tbEmail" runat="server" class="loginNormal"
Text="Click here to enter Email." /><br />
<br />
<input id="Submit10" type="submit" value="Register">
</div>
TextBox before typing information.TextBox after typing information.

Now on aspx page you only have to add Theme="Default" in page definition tag. You can also use web.config to define this theme as your default theme. Once page gets rendered Asp.Net will automatically attach Javascript events to TextBox because we defined those in skin file for textbox element.

Bonus section

If you are not using dot net related technologies then also you can get most of benefits of this style. You could write a script which attaches events on page at page lode time. Or if you prefer copy/paste then here is code.


<script language="javascript" type="text/javascript">
addEvent(window, 'load', init, false);

function init()
{
var textBoxes = document.getElementsByTagName('input');
for (var i = 0; i < textBoxes.length; i++)
{
var theInput = textBoxes[i];

if (theInput.type == 'text')
{
/* Add event handlers */
addEvent(theInput, 'focus', textOnFocus(theInput), false);
addEvent(theInput, 'blur', textOnBlur(theInput), false);
}
}
}
</script>

Summary

Download Download source

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 :)

Wednesday, August 5, 2009

Width or No Width: that is the question

“To be, or not to be: that is the question:”
-William Shakespeare
codeproject

Width is very important element in application design. If not used wisely it can break entire screen design. Few days back i was working on fixing few bugs in one of application. QA team reported that they were not able to see a table (which was created using GridView of .net) was not displaying data properly. Here is an example of it.

Hi, my wife tried to use a credit card online by inserting it into the floppy port of our pc. I have tried to fish it out but looks like it will have to come apart to retrieve the card. Is that a easy task to do?
What would be your immediate reaction to spilling a beverage on your laptop?

Here is HTML code for this

<table cellspacing="0" cellpadding="5" border="1">
<tr>
<td>
Hi, my wife tried to use a credit card online by inserting it into the
floppy port of our pc. I have tried to fish it out but looks like it will
have to come apart to retrieve the card. Is that a easy task to do?
</td>
<td width="40%">
<select style="width: 100%">
<option>I would call GeekSquad for help.</option>
<option>I would search on web for answers.</option>
<option>I would google for an action.</option>
</select>
</td>
</tr>
<tr>
<td>
What would be your immediate reaction to spilling a beverage on
your laptop?
</td>
<td>
<select style="width: 100%">
<option>I would turn it off immediately.</option>
<option>I would cream for help.</option>
<option>I would google for an action.</option>
</select>
</td>
</tr>
</table>

This looks OK enough, right? It has 60-40 split, all text comes properly. That's what we thought initially too. When QA team reported that they were not able to see this page properly I was surprised, I requested for screenshot and they send me this.

How to Buy Inexpensive Quality Computers and Electronics?
How to Choose a Computer?

Instead of using long question text they has short questions and long responses like in above example. As they reported text in dropdown, After reviewing code I found that code for creating dropdown <select style="width"100%"> was root of problem I changed it to <select> and ... see the result.

How to Buy Inexpensive Quality Computers and Electronics?
How to Choose a Computer?

As you can see here by removing style="width:100%" dropdown expanded to accommodate text and user can see entire text in dropdown.

Here is another example, in this example I needed to display some text, this text can be few words, short statements or many words and long statements as this was free form text entered by user. UI specification was if it is short text it should come into center, if there are more then one line then all lines should be left aligned and come into center of screen, as line becomes wide it shold automatically change it's position to be in center till line can not fit in same row at that time it should fall into next row. Here are few examples of this.

Example: 1
To create this table you should follow these steps.
  1. open ms-word
  2. select insert -> table
  3. select number of rows and columns you need.
  4. use that table


Example: 2
To create this table you should follow these steps.
1) open ms-word. 2 ) select insert -> table. 3) select number of rows and columns you need. 4) use that table

As you can see here in both of above examples text gets adjusted automatically according to width.
Here is code for it.


<table width="100%">
<tr>
<td align="center">
<table>
<tr>
<td align="left">
To create this table you should follow these steps.
<br />
1) open ms-word. 2 ) select insert -> table.
3) select number of rows and columns you need, even after
creating table if you can change this selection if you need.
4) use that table
</td>
</tr>
</table>
</td>
</tr>
</table>

The trick here is not to define width for inner table. By not defining width for inner table it will expand to accommodate longest text and will automatically come to next row if text is more then one row and align="center" on outer <td> will keep inner table into center all the time.


"Using width can be very tricky and can produce unexpected results some time, specially if input is controlled by user, in this kind of situations use minimum width and maximum width as text input to avoid any 'surprises' "

Saturday, August 1, 2009

Why UI/UX is important?

“Programming today is a race between software-engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots.

So far, the Universe is winning”
-Rich Cook

codeproject

Many times during interviews I have been asked the above question. There could be many different answers and opinions about this; I came up with the following. If you are a system developer probably this would give you more insight and a different view of application you are working on/have worked on.


For any application UI is its face. Everyone likes beauty which applies to computer users (and users of your application too?); UI can help to create a strong brand name and good company image. By providing consistence, UI minimizes the learning curve and helps the end user to start using the system from day one. This helps to make a popular application.


As end user if I am frustrated or feel helpless with an application then probably I will wait and look for alternatives (and soon I will find one too). While designing any application if developers do not think as end users then the product fails. As an example; even though Gateway was first to launch an online ordering system, Dell got a very good start because of continuously providing a good user experience. Dell realized soon that online ordering system is not against phone ordering system but it is ‘with’ Phone ordering system. Few changes like replacing dropdown boxes with lists, radio buttons or check boxes with graphic buttons, giving clear descriptions and creating ordering wizards instead of one long ordering page boosted Dell’s sales significantly.


Following table is code line analysis for .Net Pet Shop 4.0 application.



As you can see from the above example the amount of code we write for presentation layer is very high. In most of the cases this is true as Presentation layer or UI has to provide access to various functions of an application. As presentation layer is a huge code it is very critical that it should be designed very carefully.


Windows 95Windows 95
Windows VistaWindows Vista

Everyone likes a change towards more beautiful applications. Since Microsoft launched Windows 95 in 1995 and Windows Vista in 2007 you will notice many changes, many things got more beautiful and more elegant. As an end user even if 2 applications have exactly the same functions I would be willing to pay a bit more money to get the more beautiful application.


As the application user I don’t care how ‘good’ your application is, which ‘great’ programming methodology you have used to create your application, which testing method you used, which programming technology you used, I only care about one thing, ‘How does it make my life easy?’ As a developer if you think about the above question you will win users of your application, no one likes to click 10 buttons to get a single piece of information; it has to be very simple and easy to relate to. As an application user I don’t like changes (which is contradictory to my earlier statement ‘everyone loves change’). I like change but it should be more sensible like the ‘Start’ button of Windows. Since Windows 95 introduced it in 1995, the ‘Start’ button has been on the bottom left corner of the screen. It has always been there; today, in Vista it looks different but it is still there. You have the option to move the ‘Start’ button on any side of your screen but by default it will be on the bottom left corner of your screen. Few more examples could be Close (Minimize and Restore) button, menu items, toolbar etc.


"UI is very important part of any application as it is the only way for user to access functionality of application, it can be deciding factor to make or break any application."

Happy Coding & designing :)