Monday, January 26, 2009

DataGridView Custom Cell ToolTip



Level: Intermediate

Knowledge Required:
  • DataGridView Control
  • Windows Forms
Description:
We have a built-in ToolTip for each Cell in DataGridView control. Which is displayed when the text is long and cannot be displayed completely in Cell. But my requirement was to create a custom ToolTip (as displayed in above image).

There were 2 main requirements,

1) ToolTip should be displayed permanently that is, it should NOT be disappeared automatically after sometime.
2) I want to have a fancy look of my ToolTip (again see the image).

For this purpose we can also use the .net's built-in ToolTip control. Which can have a little fancy look by setting some of its properties like IsBubble, ToolTipIcon and ToolTipTitle. Also the ToolTip control can be more customized by using OwnerDraw mode. But still I would like to use my own ToolTip window. Because to me, this is more easier to do.

Simply I implemented it by creating a new window for ToolTip and I show this window when mouse enters in a cell. But to make it more user friendly, I have used a Timer control. So that whenever mouse enters in a Cell I start timer and in Timer's Tick Event Handler, I display the ToolTip window.

Few things to be considered here,

1) DataGridView's ShowCellToolTips property should be set to False
2) Decide where to display the ToolTip window

So in my case I decided to display the ToolTip window just on the Cell. OK this is NOT just straight. We first need to get the Cell's actual Coordinate in DataGridView by executing DataGridView's GetCellDisplayRectangle() function. Then we need to convert these coordinates into Screen's Coordinates by calling the DataGridView's PointToScreen() function.

Please note that, to display our own custom ToolTip window on our given position we need to set its property StartPosition = Manual, which I have discussed in my earlier post Setting Window / Form Position Programmatically

Another thing I have added in the ToolTip window is the Close Button. Which is actually a NON Focusable button as I have discussed my previous post NOT Focusable / NOT Selectable Button

Download Source:
DataGridViewCustomCellToolTip.zip

Friday, January 23, 2009

NOT Focusable / NOT Selectable Button

Level: Intermediate

Knowledge Required:
User Controls

Description:
Few days back I was creating a user control like ComboBox. In ComboBox we have a Drop Down button at the right side, which cannot have focus. This button can only be clicked by mouse to open the Drop Down portion (Alt+Down is the shortcut).

Similarly my control also have a button on right. I decided to make that button just like the Drop Down button of ComboBox. For this purpose I added a plain Class in my project and then put the following Code,

Public Class NotSelectableButton
Inherits Button

Public Sub New()
MyBase.New()
' following line will make this button Not Focusable
SetStyle(ControlStyles.Selectable, False)
End Sub
End Class

Saturday, January 17, 2009

FTP File Upload Error

It seems that our Network Administrator has changed some settings because my previous file uploading code is NOT working. And giving the following exception:

The server returned an address in response to the PASV command that is different than the address to which the FTP connection was made.

I was using the VB.net My namespace,
My.Computer.Network.UploadFile("C:\SomeFile.txt", "ftp://ftpsite/somefile.txt", "userid", "pwd")
So I Googled about that error and found some dicussion on MSDN forums.

Then I modified and created my own upload function as,
Private Sub UploadFile(ByVal sDestination As String, ByVal sSource As String, ByVal sUserID As String, ByVal sPassword As String)
    Dim i As System.Net.FtpWebRequest
    Dim us As System.IO.Stream
    Dim filebytes As Byte()

    ' create the FTP Web Request
    i = System.Net.WebRequest.Create(sDestination)
    ' set credentials
    i.Credentials = New System.Net.NetworkCredential(sUserID, sPassword)
    ' method = Upload File
    i.Method = System.Net.WebRequestMethods.Ftp.UploadFile
    i.UsePassive = False
    i.Proxy = Nothing
    ' get the Request Stream
    us = i.GetRequestStream()
    ' get the file bytes from source
    filebytes = My.Computer.FileSystem.ReadAllBytes(sSource)
    ' write the bytes in stream
    us.Write(filebytes, 0, filebytes.Length)
    ' close the stream
    us.Close()
End Sub
Warning! Above function will read all the bytes (in one go) from file. Which is NOT a good practice for larger files.

Friday, January 2, 2009

Another way of accessing a file on Web Server (Javascript/ASP.net)

Few days back while working on back-end of a Web Portal. I was trying to create an Anchor Tag (<a>) in such a way that a log should also be created whenever that anchor tag is clicked by user.

So there are couple of techniques.

Approach #1:
On Click: Post back to server create the log and redirect to the URL.

Approach #2:
Use AJAX

So I used the 2nd approach. For this purpose I first created a Javascript function as,

First Try:
function createlog(param1, param2) {
var xmlHttp;
try
{ // Firefox, Opera 8.0+, Safari
xmlHttp=new XMLHttpRequest();
}
catch (e)
{ // Internet Explorer
try
{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
alert("Your browser does not support AJAX!");
return false;
}
}
}
try
{
var u;
u = "createlog.aspx?param1=" + param1 + "&param2=" + param2;
xmlHttp.open("POST", u, false);
xmlHttp.send(null);
return true;
}
catch (e)
{
return false;
}
}


So this is an example function. Which will create a log by executing a "createlog.aspx" file on server which accepts 2 parameters in QueryString. The above function is simply using the XMLHttpRequest() object for AJAX call.

Then we can use this function in an anchor tag as,
<a href="http://www.domain.com" onclick="return createlog(1, 2);">www.domain.com</a>

When user will click on the link the createlog() function will be executed first. Which then will create the log on server and then redirect to the link.

Second Try:
Secondly I looked in the Google's Result Page. Because they are doing this also. Whenever we click on a result, Google redirects to that URL directly (without posting back) but also keeps the track of clicking. I looked into their Javascript and found a very interesting thing. And hence modified my Javascript function to this,
function createlog(param1, param2) {
var u = "createlog.aspx?param1=" + param1 + "&param2=" + param2;
(new Image).src = u;
return true;
}


Because my requirement is to just execute the "createlog.aspx" file on the server. I do NOT need the returned value. That is why XMLHttpRequest() is NOT critically required in this scenario. On the other hand (new Image).src approach is lot simpler.

What happens is that the browser creates an Image object and go to the "source" (in this case my createlog.aspx) which actually do NOT return any data (i.e. image bytes). But by going to that URL it actually is executed on server. And the Image object is then discarded at the end of function (I guess).


One more thing I found was Google is using "onmousedown" event instead of "onclick". I don't know exactly the benefits but I have experience that "onclick" event is NOT fired (on some browsers) when we right click and open the link in new window or tab. "onmousedown" event is triggered each time we click on link even if we right click on it. So it seems that this is NOT a good approach to use "onmousedown". But I have checked that whenever we right/left click on the link for the first time, the file "createlog.aspx" is executed on server. But it does NOT execute, if we click again. I think this is due to cache maybe.