Friday, September 9, 2011

Filtering Arrays Using LINQ

LINQ provide a fast and effective way to filter arrays.

Here is an example on how to get the unique/distinct content of an array:
'An example array
Dim dArray() As Integer = {4, 5, 6, 7, 8, 5}

'Filter by LINQ
'dResult will contain the result.
Dim dResult = (From dNumber As Integer In dArray
               Select dNumber).Distinct

'Display the number of results
MessageBox.Show(dResult.Count)

Using StringBuilder

StringBuilder is very useful if you are working on string with a lot of concatenation. String has its own limitation and is very slow when you do a lot of string manipulations.

Here is an example of using StringBuilder:

Import System.Text
Imports System.Text

Example using Append method.
Dim dString As New StringBuilder
dString.Append("This is a string. ")
dString.Append("This is another string.")

The output of this will be: "This is a string. This is another string."

Example using AppendFormat method
Dim dString As New StringBuilder
Dim dString1 As String = "Append"
Dim dString2 As String = "Format"
dString.AppendFormat("This is a string using {0}{1},", dString1, dString2)

Creating and Using Datatables in VB.net

DataTable is very useful in storing data in table format that can be use to display in DataGridView control or any data bound controls.

DataTable can be search/filtered using LINQ.

Here is how to create a datatable:
Dim dTable As New DataTable("TableName")

Add columns to the datatable
dTable.Columns.Add("Column1", GetType(Integer))
dTable.Columns.Add("Column2", GetType(String))
dTable.Columns.Add("Column3", GetType(Date))
dTable.Columns.Add("Column4", GetType(Double))

Add rows to the datatable
dTable.Rows.Add({1, "Hello", Now.Date, 5.6})
dTable.Rows.Add({2, "World", New Date(2011, 2, 1), Math.PI})

You can also add rows using the following code:
Dim dRow As DataRow
dRow = dTable.NewRow
dRow("Column1") = 3
dRow("Column1") = "Hello World"
dRow("Column1") = Now.Date
dRow("Column1") = 4.6
dTable.Rows.Add(dRow)

To bind the datatable to the DataGridView control:
'Change DataGridView1 to the name of your DataGridView control
DataGridView1.DataSource = dTable

To filter the datable, you can use any of the two codes.
'Filtering using DataTable.Select() method
'This method is very slow if you have a lot of rows.
Dim dResult1() As DataRow = dTable.Select("Column1 = 3")

'Filtering using LINQ.
'This is the recommended approach if you are working on large set of data.
Dim dResult2 = From dItem As DataRow In dTable.AsEnumerable
              Where dItem("Column1") = 3
              Select dItem

To convert DataTable to HTML you can read this article:
Convert DataTable to HTML Table

How To Capture Keys If KeyDown Event Is Not Firing

To force the KeyDown and KeyUp event to capture keys like left, right, up, and down keys, IsInputKey must be overriden.

Here is the code that will show you how to do it.

Protected Overrides Function IsInputKey(keyData As System.Windows.Forms.Keys) As Boolean
    Select Case keyData
        Case Keys.Left, Keys.Right, Keys.Up, Keys.Down
            Return True
        Case Else
            Return MyBase.IsInputKey(keyData)
    End Select
End Function

If there are keys that are not firing the KeyDown and KeyUp event, just place it after the Keys.Down in the select case statement.

Monday, August 15, 2011

Get the Exact Width of A String Using MeasureCharacterRanges

Getting the exact size of a string will not always work using MeasureString. Here is the remark coming the MSDN website:

The MeasureString method is designed for use with individual strings and includes a small amount of extra space before and after the string to allow for overhanging glyphs. Also, the DrawString method adjusts glyph points to optimize display quality and might display a string narrower than reported by MeasureString.

So to obtain the actual size, MSDN continues:
"...To obtain metrics suitable for adjacent strings in layout (for example, when implementing formatted text), use the MeasureCharacterRangesmethod or one of the MeasureString methods that takes a StringFormat, and pass GenericTypographic. Also, ensure the TextRenderingHint for the Graphics is AntiAlias.

Here is the code on how to obtain the exact size using MeasureCharacterRanges:

Public Function MeasureDisplayStringWidth(ByVal dGraphics As Graphics, ByVal dText As String, ByVal dFont As Font) As Integer	
	Dim dRect As New System.Drawing.RectangleF(0, 0, Integer.MaxValue, Integer.MaxValue)
    Dim dRange As System.Drawing.CharacterRange() = {New System.Drawing.CharacterRange(0, dText.Length)}
    Dim dRegion As System.Drawing.Region() = New System.Drawing.Region(0) {}
    Dim dFormat As New System.Drawing.StringFormat()

    dFormat.SetMeasurableCharacterRanges(dRange)

    dRegion = dGraphics.MeasureCharacterRanges(dText, dFont, dRect, dFormat)
    dRect = dRegion(0).GetBounds(dGraphics)
	Return CInt(Math.Truncate(dRect.Right + 1))
End Function