Compact Framework DataGrid Alternating Color

by Ken Tucker 19. October 2007 17:01

One of the things I miss from the Windows Forms DataGrid is the ability to have the rows alternating in color.  For this example I created a custom DataGridTextBox column which will display each other row in an different color. Basically I override the paint method to call the existing paint method with a different back color brush for every other column.

 

Public Class AltColorColumn
    Inherits DataGridTextBoxColumn

    Private m_AltColor As Color
    Public Property AltColor() As Color
        Get
            Return m_AltColor
        End Get
        Set(ByVal value As Color)
            m_AltColor = value
        End Set
    End Property

    Protected Overrides Sub Paint(ByVal g As System.Drawing.Graphics, ByVal bounds As System.Drawing.Rectangle, ByVal source As System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer, ByVal backBrush As System.Drawing.Brush, ByVal foreBrush As System.Drawing.Brush, ByVal alignToRight As Boolean)
        If rowNum Mod 2 = 0 Then
            MyBase.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight)
        Else
            Dim bb As New SolidBrush(m_AltColor)
            MyBase.Paint(g, bounds, source, rowNum, bb, foreBrush, alignToRight)
            bb.Dispose()
        End If
    End Sub

    Public Sub New()
        m_AltColor = Color.LightSkyBlue
    End Sub
End Class

 

To test the column style I added the Northwind Sql Compact edition database and let it create a typed dataset for the products table for me.  While compiling the project I got a few errors in the designer generated code for the typed dataset. The compact framework does not support the dispose method for the memory stream.  You can comment out the few lines of code safely

 

Finally
    If (Not (s1) Is Nothing) Then
        's1.Dispose
    End If
    If (Not (s2) Is Nothing) Then
        's2.Dispose
    End If
End Try

 

Here is the code I used to generate a datagrid with alternating color columns.

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim bs As New BindingSource
        Dim dt As New NorthwindDataSet.ProductsDataTable
        Dim ta As New NorthwindDataSetTableAdapters.ProductsTableAdapter

        ta.Fill(dt)

        bs.DataSource = dt

        Dim ts As New DataGridTableStyle
        ts.MappingName = dt.TableName

        Dim colName As New AltColorColumn
        With colName
            .Width = 150
            .HeaderText = "Product Name"
            .MappingName = "Product Name"
        End With

        Dim colPrice As New AltColorColumn

        With colPrice
            .Width = 75
            .HeaderText = "Price"
            .MappingName = "Unit Price"
            .Format = "c"
        End With

        ts.GridColumnStyles.Add(colName)
        ts.GridColumnStyles.Add(colPrice)
        DataGrid1.TableStyles.Add(ts)
        DataGrid1.DataSource = bs
    End Sub
End Class

Vista: Get WinSat Info

by Ken Tucker 22. March 2007 04:12

Vista: Get WinSat Info



Windows Vista has a performance index for your hardware.  The scores range from 1(worst) to 5.9(best).  If your application uses a lot of graphics you might get poor performance on a computer with a graphics score of 1.  You can use this number to scale back on the graphics to improve your apps performance.  This example gets displays the scores in the forms paint event.  For this example add a reference to the WinSat 1.0 type library in the com tab.


Imports WINSATLib
Imports System.Text

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        Dim ws As New CQueryWinSAT
        Dim sbInfo As New StringBuilder

        For x As Integer = 0 To 4
            Dim info As IProvideWinSATAssessmentInfo = ws.Info.GetAssessmentInfo(x)
            sbInfo.Append(info.Title & vbCrLf)
            sbInfo.Append(info.Description & vbCrLf)
            sbInfo.Append(info.Score & vbCrLf & vbCrLf)
        Next

        e.Graphics.DrawString(sbInfo.ToString, Me.Font, Brushes.Black, 0, 0)
    End Sub
End Class

Vista: File System Transactions

by Ken Tucker 22. March 2007 04:12

Vista: File System Transactions



Windows Vista has several new functions for using transactions when working with files.  Here is an example on how to create a transaction, work with some files, and commit it.


Imports System.Runtime.InteropServices
Imports Microsoft.Win32.SafeHandles
Imports System.IO


Module Module1

    Public Declare Auto Function CreateTransaction Lib "Ktmw32.dll" (ByVal Attributes As IntPtr, _
        ByVal guid As IntPtr, ByVal options As Integer, ByVal isolationlevel As Integer, _
        ByVal isolationflags As Integer, ByVal milliseconds As Integer, ByVal description As String) As IntPtr

    Public Declare Auto Function RollbackTransaction Lib "Ktmw32.dll" (ByVal handle As IntPtr) As Boolean

    Public Declare Auto Function CommitTransaction Lib "Ktmw32.dll" (ByVal handle As IntPtr) As Boolean

    Public Declare Auto Function CloseHandle Lib "Kernel32.dll" (ByVal handle As IntPtr) As Boolean

    Public Declare Auto Function CreateFileTransacted Lib "Kernel32.dll" (ByVal fileName As String, _
        ByVal desiredAccess As Integer, ByVal ShareMode As Integer, ByVal SecurityAttributes As IntPtr, _
        ByVal CreationDisposition As Integer, ByVal FlagsAndAttributes As Integer, _
        ByVal hTemplateFile As IntPtr, ByVal transaction As IntPtr, _
        ByVal miniversion As IntPtr, ByVal extendedOpenInfo As IntPtr) As SafeFileHandle

    Public Declare Auto Function DeleteFileTransacted Lib "Kernel32.dll" (ByVal fileName As String, _
        ByVal transaction As IntPtr) As Boolean

    Private Const GENERIC_READ As Integer = &H80000000
    Private Const GENERIC_WRITE As Integer = &H40000000
    Private Const CREATE_NEW As Integer = 1
    Private Const CREATE_ALWAYS As Integer = 2
    Private Const OPEN_EXISTING As Integer = 3

    Sub Main()
        Using sw As StreamWriter = File.CreateText("test1.txt")
            sw.WriteLine("This is the first file")
        End Using

        Using sw2 As StreamWriter = File.CreateText("test2.txt")
            sw2.WriteLine("The other file")
        End Using

        Console.WriteLine("Before delete")
        Console.WriteLine("------------------")
        Dim diBefore As New DirectoryInfo(My.Application.Info.DirectoryPath)
        For Each fi As FileInfo In diBefore.GetFiles
            Console.WriteLine(fi.Name)
        Next
        Console.WriteLine("------------------")
        Console.WriteLine("After transaction delete")
        Dim tx As IntPtr = CreateTransaction(IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, Nothing)
        Dim b As Boolean = DeleteFileTransacted("test1.txt", tx)
        Dim sh As SafeFileHandle
        sh = CreateFileTransacted("SafeTest.txt", GENERIC_READ Or GENERIC_WRITE, 0, IntPtr.Zero, CREATE_NEW, 0, IntPtr.Zero, tx, IntPtr.Zero, IntPtr.Zero)

        Dim fst As New FileStream(sh, FileAccess.Write)
        Dim swt As New StreamWriter(fst)
        swt.WriteLine("Hello World")
        swt.Close()

        For Each fi As FileInfo In diBefore.GetFiles
            Console.WriteLine(fi.Name)
        Next
        Console.WriteLine("------------------")
        Console.WriteLine("After commit delete")
        CommitTransaction(tx)

        For Each fi As FileInfo In diBefore.GetFiles
            Console.WriteLine(fi.Name)
        Next
        CloseHandle(tx)


    End Sub

End Module

List Vista RSS feeds

by Ken Tucker 21. March 2007 04:12

List Vista RSS feeds



To list the RSS feeds added to IE7 in windows Vista add a reference to Microsoft.Feeds 1.0. You will find it in the com tab. 


Imports Microsoft.Feeds.Interop

Public Class Form1
    Dim mgr As New FeedsManager
    Dim fldr As IFeedFolder

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        fldr = mgr.RootFolder

        ListFeeds(fldr)

    End Sub

    Private Sub ListFeeds(ByVal fldr As IFeedFolder)
        For Each feed As IFeed In fldr.Feeds
            Trace.WriteLine(feed.Name)
            ListItems(feed)
        Next
        For Each f As IFeedFolder In fldr.Subfolders
            Trace.WriteLine(f.Name)
            ListItems(f)
        Next
    End Sub

    Private Sub ListItems(ByVal feed As IFeed)
        Trace.Indent()
        For Each item As IFeedItem In feed.Items
            Trace.WriteLine(item.Title)
        Next
        Trace.Unindent()
    End Sub
End Class

Vista Updates and Tools

by Ken Tucker 7. March 2007 06:12

Vista Updates and Tools



First the Visual Studio 2005 SP1 update for Vista has been released.


Service Pack 2 for SQL Server 2005 is out. This is the only version of SQL Server 2005 that is supported on Vista.


Finally the free Virtual PC 2007 is available

Vista Application Recovery

by Ken Tucker 9. December 2006 06:12

Vista Application Recovery


Ever want to add the ability to recover the user data if your application has crashed. Windows Vista has some nice apis to make this easy.


The RegisterApplicationRestart api tells Vista we would like the app to restart if it crashes or hangs. This api takes two arguments a string which will be the command line argument when the application restarts and RestartFlags. For this example we will tell the app to always restart. Note the app must run 60 seconds before it will restart.



    Enum RestartFlags
        Always = 0
        Cyclical = 1
        NotifySolution = 2
        NotifyFault = 4
        DoNotRestartOnCrash = 8
        DoNotRestartOnHang = 16
        DoNotRestartOnUpdate = 32
    End Enum

    Declare Auto Function RegisterApplicationRestart Lib "kernel32.dll" (ByVal strMessage As String, ByVal RestartOption As RestartFlags) As Integer

RegisterApplicationRestart("Restarted", RestartFlags.Always)



 

The RegisterApplicationRecoveryCallback will allow us to register a function to run if our application crashes or hangs. This will allow us to save the users work before the app terminates. Note that you will not have access to the forms controls but you will have access to the variables. If you want to be able to recover the text in a textbox I would use a variable which is updated in the textboxes textchanged event. Inside the callback function you must tell Vista you are working with the ApplicationRecoveryInProgress function. When the recovery is complete tell Vista with the ApplicationRecoveryFinished function.



    Declare Auto Function RegisterApplicationRecoveryCallback Lib "kernel32.dll" (ByVal cb As App_Recovery_Callback, ByVal Param As String, ByVal PintInterval As Integer, ByVal flags As RestartFlags) As Integer
    Declare Auto Function ApplicationRecoveryInProgress Lib "kernel32.dll" (ByRef Canceled As Boolean) As Integer
    Declare Auto Function ApplicationRecoveryFinished Lib "kernel32.dll" (ByRef Success As Boolean) As Integer

    Delegate Function App_Recovery_Callback(ByVal Param As String) As Integer


    Private Function Recover(ByVal Param As String) As Integer
        Dim b As Boolean
        Using sw As New StreamWriter("Recovered.txt", False)
            ApplicationRecoveryInProgress(b)
            sw.WriteLine(strTextbox)
            ApplicationRecoveryInProgress(b)
            sw.Flush()
            sw.Close()
        End Using
        ApplicationRecoveryFinished(True)

        Return 0
    End Function

One last thing. The .Net framework will catch the error and prevent our recovery callback function from being called. So we need to uncheck the enable application framework box in my projects so we can make the application start with Sub Main. In Sub Main we can Set the UnHandledException Mode to throw exception so Vista will know about the crash


    Public Shared Sub Main()
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)
        Application.Run(New Form1)
    End Sub


For the sample Application I have a form with a label (label1), textbox (textbox1), 2 buttons (btnCrash an btnHang), and a timer. The timer is used to update the label with how long the app ran. The 2 buttons will hang or crash the app. Here is the code for the sample app. For the app recovery to work run the program without debugging (ctrl+F5).



Imports System.IO

Public Class Form1
    Enum RestartFlags
        Always = 0
        Cyclical = 1
        NotifySolution = 2
        NotifyFault = 4
        DoNotRestartOnCrash = 8
        DoNotRestartOnHang = 16
        DoNotRestartOnUpdate = 32
    End Enum

    Dim strTextbox As String

    Declare Auto Function RegisterApplicationRestart Lib "kernel32.dll" (ByVal strMessage As String, ByVal RestartOption As RestartFlags) As Integer
    Declare Auto Function RegisterApplicationRecoveryCallback Lib "kernel32.dll" (ByVal cb As App_Recovery_Callback, ByVal Param As String, ByVal PintInterval As Integer, ByVal flags As RestartFlags) As Integer
    Declare Auto Function ApplicationRecoveryInProgress Lib "kernel32.dll" (ByRef Canceled As Boolean) As Integer
    Declare Auto Function ApplicationRecoveryFinished Lib "kernel32.dll" (ByRef Success As Boolean) As Integer

    Delegate Function App_Recovery_Callback(ByVal Param As String) As Integer

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Static x As Integer = 0
        Label1.Text = String.Format("App running {0} seconds", x)
        x += 1
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        If My.Application.CommandLineArgs.Count > 0 Then
            TextBox1.Text = My.Computer.FileSystem.ReadAllText("Recovered.txt")
            ApplicationRecoveryFinished(True)
        End If

        'register app to restart
        RegisterApplicationRestart("Restarted", RestartFlags.Always)

        'setup the Recovery Callback
        RegisterApplicationRecoveryCallback(AddressOf Recover, "Recover Data", 50000, RestartFlags.Always)
        'start a timer to show how long the app has run
        Timer1.Interval = 1000
        Timer1.Enabled = True

    End Sub

    Private Function Recover(ByVal Param As String) As Integer
        Dim b As Boolean
        Using sw As New StreamWriter("Recovered.txt", False)
            ApplicationRecoveryInProgress(b)
            sw.WriteLine(strTextbox)
            ApplicationRecoveryInProgress(b)
            sw.Flush()
            sw.Close()
        End Using
        ApplicationRecoveryFinished(True)

        Return 0
    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCrash.Click
        Throw New Exception("Crash Me!!!")
    End Sub

    Public Shared Sub Main()
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)
        Application.Run(New Form1)
    End Sub

    Private Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
        strTextbox = TextBox1.Text
    End Sub

 

    Private Sub btnHang_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHang.Click
        Do While True
            ' lock me up
        Loop
    End Sub
End Class

 

Daniel Moth and Bart De Smet's have some nice blog entries about using app recovery with c# console apps. You can register your application (a digital signature is required) at the Windows Quality Online Services site to be able to see any error reports sent by your app.

Vista Task Dialog

by Ken Tucker 7. December 2006 11:12

Vista Task Dialog


Windows Vista has some cool looking new Dialog's. This example will show how to use the TaskDialog an improved message box with Visual Studio 2005.

 


Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim x As Integer
        TaskDialogHelper.TaskDialog(Me.Handle, IntPtr.Zero, "Title", "Are you sure?", "This is a test", TaskDialogHelper.TaskDialogButtons.Ok, TaskDialogHelper.TaskDialogIcon.Question, x)
    End Sub
End Class

Public Class TaskDialogHelper
    Public Enum TaskDialogButtons
        Ok = &H1
        Cancel = &H8
        Yes = &H2
        No = &H4
        Retry = &H10
        Close = &H20
    End Enum

    Public Enum TaskDialogIcon
        Information = UInt16.MaxValue - 2
        Warning = UInt16.MaxValue
        [Stop] = UInt16.MaxValue - 1
        Question = 0
        SecurityWarning = UInt16.MaxValue - 5
        SecurityError = UInt16.MaxValue - 6
        SecuritySuccess = UInt16.MaxValue - 7
        SecurityShield = UInt16.MaxValue - 3
        SecurityShieldBlue = UInt16.MaxValue - 4
        SecurityShieldGray = UInt16.MaxValue - 8
    End Enum

    Public Enum TaskDialogResult
        None
        OK
        Cancel
        Yes = 6
        No = 7
        Retry = 4
        Close = 8
    End Enum

    Public Declare Auto Function TaskDialog Lib "comctl32.dll" (ByVal hWnd As IntPtr, ByVal hInstance As IntPtr, _
        ByVal WindowTitle As String, ByVal MainInstruction As String, ByVal Content As String, _
        ByVal CommonButton As Integer, ByVal DialogIcon As Integer, ByRef PushedButton As Integer) As Integer

End Class