|
|
by Admin
2. September 2010 05:44
While implementing a high performance search functionality for a site, I ran into some interesting
issues with some UI aspects. So I thought I would share it with everybody so you have answers to
some of the following questions when you run into similar issues.
-
How to set focus in text box at page load time
This is a very common requirement that when you are implementing a search box for your site, you
want the users to be able to start typing in search keywords when the page load. Well it is pretty
simple by using a small javascript on the page. Since Microsoft shipd jQuery with
Visual Studio now and jQuery provides very concise implementation of some
very common tasks, so I used jQuery to accomplish the task. Following snippet shows
how to use jQuery to set focus on text box.
$(document).ready(function () {
var keywordTextBox = $get("<%=keywordTextBox.ClientID%>");
keywordTextBox.focus();
}
Yes, I could have done whole thing in one line instead of storing the element in local
variable first. But I needed this element for some other user as well. Soon you will see
why. The code simple translates to when document has been loaded and DOM is ready
get text box html element and call focus method to set focus on it.
-
How to set cursor position at end of text in text box
Now that you have seen how to set focus on text box, next thing you will run into is that when
page post backs when you have text in search text box, the focus is set on the text box but
it is set at the start of the text. What you are really looking for is that when you have some
text in text box, the focus should be set at the end of the text so user can either continue
with what is already there or start deleting for a new search term. The following snippet shows
how you can use setSelectionRange or createTextRange depending
on browser, javascript method on text box to set the cursor at the end of the text in text box. Or
for that matter you can use this technique to set cursor in text box at any position.
$(document).ready(function () {
try {
var keywordTextBox = $get("<%=keywordTextBox.ClientID%>");
if (null != keywordTextBox) {
var pos = keywordTextBox.value.length;
if (keywordTextBox.setSelectionRange) {
keywordTextBox.setSelectionRange(pos, pos);
}
else if (keywordTextBox.createTextRange) {
var textRange = keywordTextBox.createTextRange();
textRange.collapse(true);
textRange.moveEnd("character", pos);
textRange.moveStart("character", pos);
textRange.select();
}
keywordTextBox.focus();
}
});
-
How to handle enter key click in text box to submit page
Now that we have set focus in text box. Now your user should be able to enter some text
in the text box and hit ENTER key to perform search. Following code snippet
shows how you can hook key events of your text box to look for ENTER key
press and then submit the page.
$(document).ready(function () {
try {
var keywordTextBox = $get("<%=keywordTextBox.ClientID%>");
if (null != keywordTextBox) {
var pos = keywordTextBox.value.length;
if (keywordTextBox.setSelectionRange) {
keywordTextBox.setSelectionRange(pos, pos);
}
else if (keywordTextBox.createTextRange) {
var textRange = keywordTextBox.createTextRange();
textRange.collapse(true);
textRange.moveEnd("character", pos);
textRange.moveStart("character", pos);
textRange.select();
}
keywordTextBox.focus();
$("input").keydown(function (e) {
if (e.keyCode == 13) {
__doPostBack("<%=searchButton.UniqueID%>", "");
return false;
}
});
}
});
The above code javascript snippet demonstrates all three features of handling various
text box features together. You can see all this in real action at the following page.
Live Demo Of Text Box Features
by Admin
12. August 2010 10:05
Linq is one of the best things that has happened in recent past in
.Net framework world. It has made data manipulation so much easy. Yes, Linq has its own
set of limitations but for most part it does the job. For those special cases you can
always go back to classic ways. In this post, I will describe use of Linq for Sql and provide
some simple answers to questions like:
- How to connect to database using Linq?
- How to query data from a table using Linq?
- How to use Linq with GridView, DataGrid etc.?
Namespace and reference to use Linq with Sql
The classes that you need to use Linq with Sql live in System.Data.Linq namespace. So
in your project you will have to add the following line at top of your source code file.
using System.Data.Linq;
This namespace lives in System.Data.Linq assembly. That means that you will have to
add reference to this assembly in your project. Now you are all set to us Linq.
How to connect to the databae?
You have been using ADO.Net for a while now and first thing we all do is have a connection object
that will be used to connect to database, open it and later on close it. Well when you are using, all
that plumbing is taken care of for you by Linq frameework. The entry point to all actions in Linq for
Sql is DataContext object. This object takes care of establishing connection with
the database. You can provider either a connection string or connection object to
create instance of DataConext object. Rest will get taken care of for you.
var dataContext =
new DataContext(ConfigurationManager.ConnectionStrings["blogengine"].ConnectionString);
Query data using Linq
Now you have set up DataContext object, it is time to get some data from the database.
You will notice that DataContext object provides methods like GetTable, ExecuteQuery,
ExecuteCommand etc. All the methods that return collection of data, expect another parameter
which is Type of an object that represent the data returned from query or command. In
otherwords, the method is looking for a mapping between table in the database to an object. Here is
an object definition that I used in my code to map to fields from a datatable that I wanted to fetch.
[Table(Name="be_Posts")]
public class BlogPost
{
[Column(IsPrimaryKey=true)]
public Guid PostID
{get;set;}
[Column]
public string Title
{get;set;}
[Column]
public string MiniUrl
{get;set;}
}
There are few attributes on this class that are to be notices. First, there is TableAttribute
on the class itself. By default Linq assumes that name of the class or object is same as table in the
database. But if your table name does not match with the class name, then you can use this attribute to
provide the name of the table that maps witht this obejct. For example in my case table name be_Posts
is to be mapped to BlogPosts object which is my ViewModel. Next attribute is ColumnAttribute.
You will assign this attribute to properties or fields that needs to be queried. If your column name does
match with name of the property or field, you can provide that mapping as well. There are more values you
can set in the column attribute. I will discuss those in subsequent posts. For now this simple
definition of .Net object will work for our simple query purposes.
Bind Linq To GridView
Now we have our Linq query set to go, rest is just setting this collection to our GridView
object on ASP.Net page and rest is all taken care of for us. Following code snippet
shows how in few lines we are able to connect to database, query the data and bind it to a GridView.
void BindGrid()
{
var dataContext =
new DataContext(ConfigurationManager.ConnectionStrings["blogengine"].ConnectionString);
var posts = dataContext.GetTable<BlogPost>();
postsGridView.DataSource = posts;
postsGridView.DataBind();
}
It is as simple as these 4 lines of code to connect to database, query the table and bind to a gridview using
Linq to Sql.
by Admin
3. June 2010 04:52
Download Source Code (9.09 kb)
Download Binaries (6.28 kb)
Recently I started created some YouTube videos and wanted to embed them in my ASP.Net web site. YouTube
provides Embed button next to each video and that helps you create HTML code that you can
put on your page. But that would mean that you will have to hard code this HTML on all pages
where you want to embed videos. Also if you want to show some random videos on the pages, then this
approach is not flexible.
I created this ASP.Net server control that allows to embed YouTube videos on any page. The control allows
you to embed videos for which you already have URL or you can configure it to fetch any of the standard
YouTube feeds and then display random video from that feed.
How to use it?
- Download source code of the control and compile it or download pre-compiled binaries of the control.
- Add reference to ByteBlocks.YouTubeWeb assembly in your project.
-
On the page where you want to embed YouTube video, add the following directive at the top of the page.
<%@ Register TagPrefix="ByteBlocks" Assembly="ByteBlocks.YouTubeWeb"
Namespace="ByteBlocks.Web.Control" %>
-
Now add the control on the page.
<ByteBlocks:YouTube id="youTubeVideo" runat="server" Width="480" Height="385"
VideoUrl=""
FeedType="MostRecent" RandomResults="true" />
- And you are all set to show random video from Most Recent video feed from YouTube.
Configurable Properties
- VideoUrl: This property allows you to set URL of the video that needs to be embeded.
- Width: Sets the width of the video player
- Height: Set the height of the videeo player
- FeedType: If you do not want to use a pre-defined video URL, you can pick a standard
feed type. The control will fetch that feed from YouTube and display it based on value set for
RandomResults and IndexToShow. This property is mututally exlcusive
with VideoUrl. If you want the control to fetch standard feed, then do not set any
URL in VideoUrl.
- RandomResults: This property indicates to control to pick a random Video Url from
the list of videos from standard feed type.
- IndexToShow: If you set RandomResults to false, then the control
will fetch the video at this index value. If this index is out of range, then the control picks the
last entry in the feed list.
Under the covers
When you generate HTML code for a video from YouTube, it looks something like as shown below.
<object width="480" height="385">
<param name="movie" value="http://www.youtube.com/v/XcugLsKDmRs&hl=en_US&fs=1&rel=0"></param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed src="http://www.youtube.com/v/XcugLsKDmRs&hl=en_US&fs=1&rel=0"
type="application/x-shockwave-flash" allowscriptaccess="always"
allowfullscreen="true" width="480" height="385"></embed>
</object>
So the control simply renders this HTML on ASP.Net page and uses the control properties to
configure the display accordingly. The important components of this HTML is video ID used with the
video player. I have shown that in bold in snipper above. A video URL looks like as shown below.
http://www.youtube.com/watch?v=Qp9_6ACSWug
Video ID is provided in v query string parameter. The control parses this ID and
replaces it in the URL that is required for URL for video player.
Source Code and Binaries
Attached code is compiled using Visual Studio 2010 and .Net 4.0 framework. If you need code for
earlier versions of Visual Studio, feel free to conttact me.
by Admin
5. November 2009 06:34
When we are creating a web site, one of the main goal we all have is that out site should be listed on first page of search engines like Google, Bing, Yahoo, Baidu etc. As we all know that in SEO world, one of the first thing we all look for in the page is meta tags in header of the page. In the past there was no direct way to set the meta tags on a page programatically when developing ASP.Net web site. We all used the work around of adding metaelements in header element of the page. You can read my previous post Adding meta tags to asp.net page dynamically about that technique. With ASP.Net 4.0 microsoft has introduced following two properties on that allow you to set the meta tags on a page.
- MetaDescription
- MetaKeywords
Following code snippet shows how it is used in your code.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
SetMetaTags();
}
private void SetMetaTags()
{
Title = "Hello Meta";
MetaDescription = "This is description of my ASP.Net 4.0 page.";
MetaKeywords = "ASP.Net,.Net4.0,Meta";
}
}
And it works. You can see from the source of the page as shown below.
<head>
<title>Hello Meta</title>
<meta name="description" content="This is description of my ASP.Net 4.0 page." />
<meta name="keywords" content="ASP.Net,.Net4.0,Meta" />
</head>
by Admin
6. August 2009 06:07
I have been working with VS2010 and ASP.Net 4.0 for quite some time now. Every time i create a web application, I just use the handy feature of Visual Studio of creating virtual directory for web application. Last week I was manually creating virtual directory for a web application using IIS manager. Since the application was targeting ASP.Net 2.0, so from ASP.Net tab of IIS, I selected V2.0 framework. Now there is a confirmation dialog box that comes up when you change ASP.Net framework.
Changing the Framework version requires a restart of the W3SVC service. Alternatively, you can change the Framework version without restarting the W3SVC service by running: aspnet_regiis.exe -norestart -s IIS-Viirtual-Path
Do you want to continue (this will change the Framework version and restart the W3SVC service)?
Everything is good so far. Moment i accessed the application in browser, I got the following error message.
Server Error in '/Foo' Application.
The application domain or application pool is currently running version 4.0 or later of the .NET Framework. This can occur if IIS settings have been set to 4.0 or later for this Web application, or if you are using version 4.0 or later of the ASP.NET Web Development Server. The <compilation> element in the Web.config file for this Web application does not contain the required 'targetFrameworkMoniker' attribute for this version of the .NET Framework (for example, '<compilation targetFrameworkMoniker=".NETFramework,Version=v4.0">'). Update the Web.config file with this attribute, or configure the Web application to use a different version of the .NET Framework.
I was little surprised because I never configured virtual directory for this application to use ASP.Net 4.0. I fired up IIS manager and went to ASP.Net tab. There it was, the application was configured to use ASP.Net 4.0. So I changed it back to use ASP.Net 2.0. Accessed the application in browser and got the same error again. I experimented with the dropdown box for ASP.Net version in IIS manager. The application will get configured to use ASP.Net 4.0 no matter what option I picked from the dropdown box. It seems that this is some bug in beta version of Visual Studio 2010 installation.

For now the work around I have been using is to let Visual Studio create virtual directory for my web application. It targets the correct ASP.Net version and modifies IIS meta data correctly.
by Admin
22. July 2009 03:03
I have been developing AJAX enabled applications before the term AJAX was coined. I have been doing it for so long that some of things that I do come kind of naturally. And one of the things that I always do is to make sure that response is not cached to ensure that client is never working on stale response even though it sent new request every few seconds. So I have a small piece of code that I pretty much use in all applications that sets some headers.
Response.ContentType = "text/plain";
Response.Expires = -1;
Response.CacheControl = "no-cache";
These are not just the only headers but gives you an idea how cache was being control. I never ran into any trouble with any applications till last week when I was told that our application is filling up Temporary Internet Files folder of the users. This was the first time ever I was reported such issue and actually this was first time I observed this behavior in my applications. So I fired up Fiddler to see whats going on with my requests. I looked at the response headers and saw the following.
First, I was not expecting to see Cache-Control: private. So that was little out of whack. Second, the expiration time was correct because I always set to an hour behind the response time to make sure that it is stale for caching. I have been using the same caching utility routine for so long that I did not suspect that something is wrong there. Then I looked inside Temporary Internet Files folder again and noticed that this was the only request that was being saved in the folder, others were not. So I looked at the implementation and found that the server side implementation for this request was not using my standard utility to set cache headers. Following is the code snippet that I ad in place. Well why i changed the implementation for this particular call is whole different story.
Response.ContentType = "text/plain";
Response.Expires = -1;
Notice that it is missing Cache-control : no-cache header. That explained everything. After I added this header, everything went back to normal. So I decided to do some experiment to observe behavior of setting different headers.
No Cache-control: no-cache header on any call
You will notice that from my earlier post How to serialize multiple AJAX calls in jQuery, I have two AJAX calls being made. And you can see from snapshot above that both are being saved in Temporary Internet File folder.
Cache-control: no-cache header set on one request only
Now you can see that only one request is being saved in the folder and other has disappeared.
Cache-Control:no-cache header set on all requests
Well, there is nothing to show here in Temporary Internet Files folder because nothing is being saved there any more. But here is the snapshot of response headers as seen in Fiddler.
Now you can see that no-cache header and pragma has been set correctly.
Set cache-control header correctly
As more and more applications are using AJAX or Web2.0 style of implementations, if you do not set these cache control headers correctly, you will see that browser cache folders will accumulate lot of entries. It is not that big of a deal as far as application working goes because this temporary cache will not grow beyond specified limits for a particular browser. But it will hurt performance of other internet sites that you visit because their content will not be found in cache and will have to reloaded from server again. Other performance hit you will take is that now browser has to spend an extra CPU cycle to save these entries on the disk.
by Admin
20. July 2009 14:31
Download Sample Project
For one of my current project, I have been using ASP.Net AJAX to make async request into my ASP.Net to get some time related data. First, I am not a big fab of ASP.Net AJAX implementation. I will not go into debate on why. There are plenty of discussions on this topic. I will just spare myself from it. Second, the application was already using jQuery for other javascript related implementation. I was like, if we are already using jQuery why have an overhead of introducing Ajax tool kit. So I started porting the implementation to use jQuery. Through this series of posts, I will describe how you can use jQuery to make AJAX calls in ASP.Net applications. Well, the client side javascript can be used in any browser. So other than the server side implementation, there is no nothing specific to ASP.Net per se.
The sample project for these articles is a time synchronization service. The idea is that I want to display clock on the client machine that will display server time. Well you can say there is no big deal with that implementation. On page load, get the server time. Save in some client side variable and run one second timer on it. Well, that works for most part. There are situations where clients are behind really slow connections that can cause of lot latency in request and response. So in those cases, by the time your response gets to the client side, the server time that you returned to client is already behind by few seconds. For applications that has users who depend very heavily on this server time, this latency of few seconds can be very critical. In this first post I am not going to go into details of algorithm that I implemented to reduce this latency adjustment over time. This first sample does a very simple task. It sends asynchronous request to server every 10 seconds. The server returns its time and then client uses that to display clock.
Server Side Implementation
I have a class ClockData that has DataContract attribute set on it. You can pretty much figure out that I am planning on converting this service to WCF service and use the framework facilities to serialize and de-serialize data as well. So I am populating this class with three pieces of data (server time, latency and a cookie) and then using DataContractJsonSerializer class to serialize the data into JSON format and sending it to client.
private void SerializeServerClockData(ClockData data, Stream strm)
{
var spSer =
new DataContractJsonSerializer(typeof(ClockData));
spSer.WriteObject(strm, data);
}
void SendResponse()
{
long ms = (long)(_serverTime - new DateTime(1970, 1, 1)).TotalMilliseconds;
var clockData = new ClockData()
{ServerTime = ms.ToString(), Latency = _latency, ResponseKey = Guid.NewGuid().ToString("N")};
Response.ContentType = "text/plain";
Response.Expires = -1;
Response.CacheControl = "no-cache";
SerializeServerClockData(clockData, Response.OutputStream);
Response.End();
}
From the code snippet above, you can see how plain and simple server side implementation is for this first sample. This will get little complicated as I get more into the actual algorithm of calculation of latency reduction.
Client Side Implementation
Since we are going to be using jQuery to make Ajax call, so we will need to include reference to jQuery javascript file. For this sample, I am going to show the AJAX request you can send using jQuery. The library has method named .getJSON that you can call to send the request. You can set the URL where request is to be sent, set the parameters that needs to be passed with request and set the callback function that should be called when request completes. It is that simple. Here is the implementation from the sample.
function getServerTime() {
cTime = firstRequest ? -1 : curTime.getTime();
$.getJSON(clockServiceUrl, { clientTime: cTime, requestKey: respKey }, gotServerTime);
}
function gotServerTime(data) {
firstRequest = false;
latency = data.Latency;
curTime = new Date(parseInt(data.ServerTime));
if (!clockTicking) createClockTimer();
createServiceTimer(defaultServiceTimer);
}
function clockTick() {
clockTicking = true;
curTime.setTime(curTime.getTime() + 1000);
elClockDisplay.text(curTime.toString());
if (latency == -1)
{ elLatencyDisplay.text(""); }
else
{elLatencyDisplay.text(latency + " ms");}
}
$(function() {
elClockDisplay = $('#clockDisplay');
elLatencyDisplay = $('#latencyDisplay');
getServerTime();
});
You can see with few lines of implementation you can use jQuery to make AJAX calls in ASP.Net application. In subsequent posts I will discuss how you can control the request little bit more instead of using .getJSON to use default settings.
by Admin
14. July 2009 14:21
Download Sample Project
This is based on a question asked by one of my blog readers.
I have 2 datagrids. Each Grid has the same amount of columns and each grid has a select column as the last column on the right added from the
"gridview/ edit Columns/ CommandField/ Add" sequence.
The first GridView has the Select column as a Link
The second GridView has the select Column as a button
I want to be able to change the text for both the Link and button in cell(4), setting them to the value in cell(1) from the same row using the GridView_RowDataBound event.
However, using "cell(4).text = cell(1).text" just overwrites the text value removing the hyperlink and button.
The behavior described in this question is as expected. When you set text of a cell in grid, it directly affects HTML that is going to be rendered. When you set text
value of a cell, it means that you are setting innerText of the cell. The column that GridView creates for command fields (Edit, Delete and Select)
are a (anchor) or button elements. So you can see what will happen if you set text value in that cell. It will wipe out those link or button
controls and replace them with simple text string.
There are properties like EditText, DeleteText and SelectText for CommandField column in grid view. If you try to
set these values using a server side method by passing it DataContainer object, you will get following exception thrown.
Databinding expressions are only supported on objects that have a DataBinding event.
System.Web.UI.WebControls.CommandField does not have a DataBinding event.
After looking at the requirements, i realized that requirements are as simple as replacing text with value from another cell in the same row. There is no need
for doing any server side tricks or things like that. I can simple put together a simple client side java script that will take values from cell 1 and put them
in whatever cell I want. Abd I came up with this small javascript solution using jQuery. This small code snippet shows how you can
manipulate GridView or DataGrid on client side using jQuery. Let me show you the client side javascript that
I added on the page. Then I will explain what this code is doing.
<script type="text/javascript">
function updateCommandLinks() {
var $gridTable = $('#productsGrid');
var rows = $gridTable.find('tbody > tr');
var slicedRows = rows.slice(1, rows.length - 2);
slicedRows.each(function() {
var cells = $(this).find('td');
var cellElem1 = cells.get(1);
var cellElem5 = cells.get(5);
$(cellElem5).find('a').each(function() {
$(this).addClass('commandlink').append(" " + cellElem1.innerText);
});
});
}
$(document).ready(function() {
updateCommandLinks();
});
</script>
The above code may look little verbose considering you can write very concise code using jQuery. But for sale of
explaining and debugging, I decided to make it little bit verbose. I am sure you can reduce it to half the lines of code that I
have written.
The implementation adds a handler for document load event. In that event handler here are the steps it follows:
- Finds the element that has id of productsGrid. In our case, that is HTML element ID of our grid view.
- In the table, it gets collection of all the rows, identified by tr tag.
- Since in my implementation I have header and pager, that adds three rows into the collection. One top row for the header
and then the last row itself will contain another table that contains a row for paging elements. To keep it simple, I decided to
use slice function to remove first and last 2 rows from collection. You will need to modify this implementation
depending on your grid rendering.
- It iterates over each row in the collection.
- For each row it then finds all cells, identified by td tag.
- In my case, I want to replace text in command links with text from second column. So I saved reference to cell at index
1 by using get function.
- Then I extracted all elements with tag a from sixth column.
- Then it iterates over collection of anchor a tags and appends text from second cell to text in each of the links.
I think that is a simple implementation that serves the purpose without making any changes on the server side. The attached project has
the complete implementation for this grid. This is a Visual Studio 2010 project. But you should be able to copy the script
from the page to your implementation.
by Admin
7. July 2009 14:46
Download Sample Project
This was a question was asked by one of my site visitors, Mike. Following is the text of the question:
This is a similar question to one you have already answered in formatting Grid Views. However there are 2 main differences.
First: I want to change the value of a column (not the format) in any row if the row preceding it has a certain value in the same column.
This question translates to How do you change value of a data grid column based on values of previous row(s). I
generalized this question to cover all previous rows and not just the proceeding row. Answer to all such questions relies on
handling events like RowDataBound or RowCreated events. When a data grid or grid view renders,
RowDataBound fires when row is being data bound and then RowCreated is fired after it has been
data bound and row has been created. So depending on at what stage of rendering you want to change behavior of a row,
you will subscribe either of these events. In the sample project, I am subscribing to RowDataBound event.
Next step is to access values from previous rows. Here you have choice. One, you can keep some local vaiable that stores values
from previous row(s) and then use them in current row event handling. Two, you can access the previous GridRow
based on index. In this sample i will discuss the approach of accessing previous row based on index and then extracting values
from certain cells.
In RowDataBound event handler, GridViewRowEventArgs provides you access to DataItem
associated with current row only. You do not have access to DataItem associated with previous rows. But at
this point, previous rows have been prepared for rendering. You have access to all the cell values associated with previous row.
You can access GridRow object of previous rows and extract text from cells that you are interested in. In the
sample project, I am accessing ListPrice from fourth column and then displaying it in current row along with price
associated with current row. Well, this does not sound like something that is very interesting or useful. But it serves the
purpose of demonstrating you will accomplish the task.
Here is the code snippet from sample project.
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
double price = -1.0;
double prevPrice = -1.0 ;
// Access the previous row.
if (e.Row.RowIndex != 0)
{
GridViewRow prevRow = this.productsGrid.Rows[e.Row.RowIndex - 1];
if (null != prevRow &&
prevRow.RowType == DataControlRowType.DataRow)
{
double.TryParse(prevRow.Cells[3].Text, out prevPrice);
}
}
var thisRowData = e.Row.DataItem as DataRowView;
if (!Convert.IsDBNull(thisRowData["ListPrice"]))
{
double.TryParse(thisRowData["ListPrice"].ToString(), out price);
}
var ctrl = e.Row.FindControl("prevPriceLabel") as Label;
if (null != ctrl)
{
ctrl.Text = string.Format("{0} - {1}", prevPrice, price);
}
}
}
Feel free to send me any request for any other grid view implementation you would like to be
answered or implemented.
by Admin
2. July 2009 05:19
Download Sample Project

While working on a car dealership listings web site, I was experimenting with inserting google maps
into the data grid. The grid will show name and address of top rated car dealers in certain
categories. And along side their information, it will show their location on google map. To accomplish
this task, I needed the longitude and latitude of car dealership's address or location. Some time back in
my earlier post
Convert Address and/or IP address to Geo Location I described how you can utilize google
map's api to convert a physical address to geo location coordinates. This is the same technique that I used in
Backyardtweets to show tweets in a specified
location. So use the google map api to get these coordinates and insert these coordinates in the
java script.
Now that you have geo location corresponding to an address, your task is to insert that little piece of
java script in each row of the data grid. The way google map java script works is that it requires
a HTML element where it can insert the map image. So I inserted a div with unique id in a cell in
each row and then passed that unique id to java script that is used to render the map. Add an event
handler for RowDataBound event and there you can add the element and register a
client script for map as well. Here is some code snippet that shows how this all is accomplished.
protected void OnDealerRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var carDealer = e.Row.DataItem as CarDealer;
var divId = string.Format("dealloc_{0}", carDealer.Id);
var mapPanel = e.Row.Cells[2].FindControl("mapPanel") as Panel;
var div = new HtmlGenericControl("div");
div.Attributes.Add("id", divId);
div.Attributes.Add("class", "mapdiv");
mapPanel.Controls.Add(div);
string js = GetGoogleMapScript(carDealer, divId);
ScriptManager.RegisterStartupScript
(this.Page, this.GetType(), "_map_" + carDealer.Id, js, true);
}
}
private string GetGoogleMapScript(CarDealer dealer, string ctlId)
{
string loc = string.Empty;
if (!string.IsNullOrEmpty(dealer.State))
{
loc = string.Format("{0},", dealer.State);
}
loc += dealer.Country;
decimal longitude, latitude;
GoogleMapUtility.GetGeoLocationFromGoogle(loc, out longitude, out latitude);
dealer.Location.Latitude = latitude;
dealer.Location.Longitude = longitude;
return GetJScriptForGeoLocations(longitude, latitude, ctlId);
}
public static string GetJScriptForGeoLocations(decimal longitude, decimal latitude, string elemId)
{
StringBuilder sb = new StringBuilder();
sb.Append("function initialize_" + elemId + "() {{");
sb.Append(" if (GBrowserIsCompatible()) {{ ");
sb.Append(" var map = new GMap2(document.getElementById(\"{0}\"));");
sb.Append(" map.setCenter(new GLatLng({1}, {2}), 13);");
sb.Append(" map.setUIToDefault();}}}} initialize_" + elemId + "();");
return string.Format(sb.ToString(), elemId, latitude, longitude);
}
The attached project with this post has all the implementation for this sample implementation. And this is
a Visual Studio 2010 project. I have not used any 2010 specific namespaces or code in this implementation so
you should be able to take all the code and move it into a VS2008 or VS2005 project. And you will need to
get key for google map api use from google as well.
Feel free to drop us a line if you have something in mind that you would like us to prototype
and write about it.
|
|