Thursday, May 1, 2008

Update - Datagridview - Sorting Numeric Columns that are not bound...

I found an example on a website that did what I mention above but does it a lot better.  Below is the pasted code

    Private Sub grd_SortCompare(ByVal sender As
Object, ByVal e As System.Windows.Forms.DataGridViewSortCompareEventArgs) Handles grdList.SortCompare
        e.SortResult = CompareEx(e.CellValue1.ToString, e.CellValue2.ToString)
        e.Handled = True
        Exit Sub
    End Sub


    Public Function CompareEx(ByVal s1 As Object, ByVal s2 As Object) As Integer

        Try
' convert the objects to string if possible.
            Dim a As String = CType(s1, String)
            Dim b As String = CType(s2, String)

' If the values are the same, then return 0 to indicate as much
            If s1 = s2 then return 0

' Look to see if either of the values are numbers
            Dim IsNum1 As Boolean = IsNumeric(a)
            Dim IsNum2 As Boolean = IsNumeric(b)

' If both values are numeric, then do a numeric compare
            If IsNum1 And IsNum2 Then
                If Double.Parse(s1) > Double.Parse(s2) Then
                    Return 1
                ElseIf Double.Parse(s1) < Double.Parse(s2) Then
                    Return -1
                Else
                    Return 0
                End If
' If the first value is a number, but the second is not, then assume the number is "higher in the list"
            ElseIf IsNum1 And IsNum2 = False Then
                Return -1
' if the first values is not a number, but the second is, then assume the number is higher
            ElseIf IsNum1 = False And IsNum2 Then
                Return 1
            Else
' If both values are non nuermic, then do a normal string compare
                Return String.Compare(s1, s2)
            End If
        Catch ex As Exception
            Console.WriteLine(ex.ToString)
        End Try

' If we got here, then we failed to compare, so return 0
        return 0
    End Function

Datagridview - Sorting Numeric Columns that are not bound to a DataSource

Or more precisely sorting Double (floating point, decimal) Columns that are not bound to a DataSource.

There are a lot of examples out there to sort datagridview columns that are bound to a datasource, but I could only find one example that had a solution to solving the problem of sorting when the data is not bound to a datasource.

This is the data that I have, in a csv file
Dharmit,Male,10.001,First
Lomesha,Female,11.001,Second
Jaymit,Male,7.001,Third
Ambrish,Male,8.001,First
Chanda,Female,172.00101,Second

The third column (lets call it Order) contains data that is not integers, they are double values.  I load it into a datagrid view by reading each line to a String Array, and then loading the array to the datagridview.

When I do a sortascending on the Order column, it sorts it as if it was String/ or Text instead of as a number.  If the Order column had values like 10, 11, 7, 8, 172 it would sort it properly, but the decimal point screws it up into thinking that it is text.  The solution to this problem is to use the SortCompare event, and to manually figure out if values are equal, greater than or less than.  Initially I didn't understand the sortResult values.  What does 1, -1, and 0 mean.  And to be honest I still don't know, just trial and error.  Some things to keep in mind.  The Data must not be be bound, and the VirtualMode must be False, and the SortCompare is called when the Sort is called, in my case I call it programatically and have set it such.  Also the code below assumes the data is numeric.

  Private Sub DataGridView1_SortCompare(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewSortCompareEventArgs) Handles DataGridView1.SortCompare
    If Double.Parse(e.CellValue1) > Double.Parse(e.CellValue2) Then
      e.SortResult = 1
    ElseIf Double.Parse(e.CellValue1) < Double.Parse(e.CellValue2) Then
      e.SortResult = -1
    Else
      e.SortResult = 0
    End If
    e.Handled = True
    Exit Sub
  End Sub



Thursday, April 3, 2008

MSVCR71.dll not found or MSVCP71.dll not found

I had an application and everything works fine in Windows XP, however when I installed the application on Vista, certain features did not work and gave me an error that MSVCR71.dll was not found.  Well, sure enough the dll wasn't on the Vista machine and it was on the other machines that I was testing on.

My initial thought was to add the dll's to the setup application.  But then I read an article that if you wanted to deploy these dll's to just add the merge module VC_User_CRT71_RTL_X86_---.msm from Program Files\Common Files\Merge Modules.  So I did this.  Right-click on your Setup application, select Add, then select Merge Module... and then select the module.  In the properties for the file, make sure you install it in the application folder and not the setup folder.  Ok, I tried this and still my application wasn't working. 

So I finally decided to just add the dll's directly.  Well, I right-clicked on the setup application, select Add, File.  And then navigated to the Windows\System32\ directory.  Found MSVCR71.dll and MSVCP71.dll (it turns out you need this one as well), and when I attempted to add them, I got a message that said that these two dll's were found in the vc_user_stl71_rtl_x86_---.msm and would I like to add that instead.  So I said "Yes", then I got a message to add VC_User_CRT71_RTL_X86_---.msm, so I said ok.  Installed the application on the Vista machine and everything worked fine.    What ends up getting installed on the Vista machine are the dll's, not the msm files.

Anyways, the moral of the story is that if you need a dll, just go straight to it, instead of trying to figure out what msm files.  The setup application is smart enough to figure out if that dll has an associated merge module.  I think :-)

Monday, March 24, 2008

Implicit conversion from 'System.Array' to '1-dimensional array of Byte' in copying the value of 'ByRef' parameter 'Value' back to the matching argument

I converted a project from VB6 to VB2003 to VB2005.

In VB6 we had the following type of code:

      Dim tempBytes() As Byte, readFileHandle As Long
      readFileHandle = FreeFile
      Open imgFile For Binary Access Read As #readFileHandle
      ReDim tempBytes(1 To LOF(readFileHandle))
      Get #readFileHandle, 1, tempBytes 'dataoffset is 0-based; GET is 1-based

What this basically did was it opened an image file and then read in the image file to a byte array.

When we converted to VB2003, the code was converted and fixed as such:
        Dim tempBytes() As Byte
        Dim readFileHandle As Integer
        readFileHandle = FreeFile()
        FileOpen(readFileHandle, imgFile, OpenMode.Binary, OpenAccess.Read, OpenShare.Shared)         '!!## errors?
        ReDim tempBytes(LOF(readFileHandle) - 1)           
        FileGet(readFileHandle, tempBytes, 1)            'dataoffset is 0-based; GET is 1-based

In converting it to VB2005, I decided to turn Option Strict ON, which gave a warning on the following line.  The warning is the subject of this post:
        FileGet(readFileHandle, tempBytes, 1)            'dataoffset is 0-based; GET is 1-based

The warning made sense, tempBytes is type Byte, and FileGet is expecting a System.Array.

The way to fix this is to cast tempBytes as an array, and the warning will go away, and it will still work.
            FileGet(readFileHandle, DirectCast(tempBytes, Array), 1)            'dataoffset is 0-based; GET is 1-based




Single Instance Applications is a lot easier in VB 2005

For more information, read the following post:

http://blogs.msdn.com/tyler_whitney/archive/2005/11/23/VB-Application-Model.aspx


From the article:

So what's a Single-Instance application?  Imagine launching an application where additional attempts to launch the app while the first one is running doesn't actually launch a new instance of the app.  Instead the original instance of the app gets notified that another launch attempt occurred.  When we introduced an application model for Visual Basic in VB 2005, one of the things we wanted to do is make it drop-dead easy to create single-instance applications.


Pretty much what you need to do in VB 2005 is to right click on your main project and go to properties. 
then select Application, then make sure you have "Enable application framework" checked.

Then check of "Make single instance application"

For the other items. I have everything checked, and the authentication mode, I chose Windows, and the shutdown mode, I chose When startup form closes, and for the Splash screen, I have code that takes care of this.

Either way, this is a lot easier than writing code in order to make this happen properly.

-- Ted


Thursday, March 13, 2008

Integer Division in VB.NET

Copied this from http://www.devx.com/vb2themax/Tip/18244

It pretty much talks about the difference between doing division with the "/" vs "\"

Use integer division operator
Use "\" instead of "/" when performing divisions between Integers. The "/" operator returns a Single value, therefore the seemingly efficient line


C% = A% / B%
actually requires three implicit conversions, two for converting the operands from Integer to Single (to prepare them for the division) and one to convert the result from Single to Integer (to complete the assignment). If you use the "\" operator you don't incur in this overhead, and the division itself is faster. While we are on this topic, keep in mind that the "/" operator returns a Double value if at least one of its operands is a Double; therefore if you wish the highest precision when dividing two Integer or Single values, you should manually coerce one of them into Double type:

' this prints 0.3333333
Print 1 / 3
' this prints 0,333333333333333
Print 1 / 3#


Tuesday, March 11, 2008

Using the ^ operator that can slow your application down

I recently had an application where we used the "^" operation to do a Power operation.

For example in order to square X, we did X^2.  It turned out that using the "^" operator was slower than using X*X, or even using Math.Pow(X, 2).  It wasn't noticeably faster if you only did this once or twice, but in our situation, we called this function millions of times, so a little improvement made a big difference.

-- Ted