HOME | SIGN UP | ACCOUNT | SUBSCRIBE | TROUBLESHOOTING | LOGIN
News · Meetings · Jobs · Downloads · Universal Thread articles · Web articles · Conference coverages · Consultants · Blogs · FAQ · User groups · Photos · Videos

Cathi Gero's .NET Tips

Cathi Gero, Prenia Software & Consulting Services
Cathi Gero, C.P.A., is founder and development director of Prenia Corporation, providing custom software applications, training, and architectural designing to businesses and developers. Cathi is a Microsoft C# MVP and is an active member of the .NET community. She has extensive experience developing applications using the .NET Framework, Visual FoxPro, SQL Server, and Crystal Reports as well as other technologies. She is a speaker at national conferences, author of white papers for Microsoft, and technical editor for the book '.NET For VFP Developers'. Most of the year Cathi travels to various companies providing onsite training, mentoring, and development experience.

Workign With Excel Inside Of Your Application
VB.NET provides two ways of working with Excel inside of your application. One approach is to use Reflection and early-binding (the only option available for C# programmers). The other approach is using last-binding by setting Option Strict Off. VB.NET is different than C# in that setting Option Strict Off, you let the compiler handle all the crud behind the scenes to use reflection. For example, here is sample Excel code which would error out if you didn't set Option Strict Off:
Dim objApp As Object
Dim objBook As Object
Dim objBooks As Object
Dim objSheets As Object
Dim objSheet As Object
Dim range As Object

' Instantiate Excel and start a new workbook.
objApp = CreateObject("Excel.Application")
objBooks = objApp.Workbooks
objBook = objBooks.Add
objSheets = objBook.Worksheets
objSheet = objSheets.Item(1)

range = objSheet.Range("A1")

'Set the range value.
range.Value = "Hello, World!"

'Return control of Excel to the user.
objApp.Visible = True
objApp.UserControl = True
If you wanted to not set Option Strict Off, then you need to use Reflection to have the code compile. This is how it is done in C#. Here is the same functionality as above but using Reflection and keeping Option Strict On:
Dim objApp_Late As Object
Dim objBook_Late As Object
Dim objBooks_Late As Object
Dim objSheets_Late As Object
Dim objSheet_Late As Object
Dim objRange_Late As Object
Dim Parameters() As Object

Try
   ' Get the class type and instantiate Excel.
   Dim objClassType As Type
   objClassType = Type.GetTypeFromProgID("Excel.Application")
   objApp_Late = Activator.CreateInstance(objClassType)

   'Get the workbooks collection.
   objBooks_Late = objApp_Late.GetType().InvokeMember( _
      "Workbooks", BindingFlags.GetProperty, Nothing, objApp_Late, Nothing)

   'Add a new workbook.
   objBook_Late = objBooks_Late.GetType().InvokeMember( _
      "Add", BindingFlags.InvokeMethod, Nothing, objBooks_Late, Nothing)

   'Get the worksheets collection.
   objSheets_Late = objBook_Late.GetType().InvokeMember( _
      "Worksheets", BindingFlags.GetProperty, Nothing, objBook_Late, Nothing)

   'Get the first worksheet.
   Parameters = New Object(0) {}
   Parameters(0) = 1
   objSheet_Late = objSheets_Late.GetType().InvokeMember( _
      "Item", BindingFlags.GetProperty, Nothing, objSheets_Late, Parameters)

   'Get a range object that contains cell A1.
   Parameters = New Object(1) {}
   Parameters(0) = "A1"
   Parameters(1) = Missing.Value
   objRange_Late = objSheet_Late.GetType().InvokeMember( _
      "Range", BindingFlags.GetProperty, Nothing, objSheet_Late, Parameters)

   'Write "Hello, World!" in cell A1.
   Parameters = New Object(0) {}
   Parameters(0) = "Hello, World!"
   objRange_Late.GetType().InvokeMember( _
      "Value", BindingFlags.SetProperty, Nothing, objRange_Late, Parameters)

   'Return control of Excel to the user.
   Parameters = New [Object](0) {}
   Parameters(0) = True
   objApp_Late.GetType().InvokeMember( _
      "Visible", BindingFlags.SetProperty, Nothing, objApp_Late, Parameters)
   objApp_Late.GetType().InvokeMember( _
      "UserControl", BindingFlags.SetProperty, Nothing, objApp_Late, Parameters)

Catch theException As Exception
   Dim errorMessage As [String]
   errorMessage = "Error: "
   errorMessage = [String].Concat(errorMessage, theException.Message)
   errorMessage = [String].Concat(errorMessage, " Line: ")
   errorMessage = [String].Concat(errorMessage, theException.Source)

   MessageBox.Show(errorMessage, "Error")
End Try

from a solution provided by Cathi Gero in Message #991453

Numeric TextBox
Here is a custom TextBox class that provides validation and numeric data entry
Option Strict On

'=====================================================================================
' Classe      :   NumericTextbox.vb
'
' Auteur      :   Eric Moreau
'
' Description   :   System.Windows.Forms.TextBox Extender
'
' Utilisation   :   1. Add a regular TextBox to your form
'               2. In the " Windows Form Designer generated code " section, 
'                 replace System.Windows.Forms.TextBox by NumericTextBox (2 places) 
'
' Historique   :
' Auteur         Date         Intervention
' ----------------- --------------- -------------------------------------------------
' Eric Moreau      2003/10/25     Création
'=====================================================================================

Imports System.ComponentModel

Public Class NumericTextBox
   Inherits System.Windows.Forms.TextBox

#Region " Windows Form Designer generated code "

   Public Sub New()
      MyBase.New()

      'This call is required by the Windows Form Designer.
      InitializeComponent()

      'Add any initialization after the InitializeComponent() call
      CustomInitialization()
   End Sub

   'UserControl overrides dispose to clean up the component list.
   Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
      If disposing Then
         If Not (components Is Nothing) Then
            components.Dispose()
         End If
      End If
      MyBase.Dispose(disposing)
   End Sub

   'Required by the Windows Form Designer
   Private components As System.ComponentModel.IContainer

   'NOTE: The following procedure is required by the Windows Form Designer
   'It can be modified using the Windows Form Designer.  
   'Do not modify it using the code editor.
   Friend WithEvents ErrorProvider1 As System.Windows.Forms.ErrorProvider
   <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
      Me.ErrorProvider1 = New System.Windows.Forms.ErrorProvider
      '
      'S2iNumericTextBox
      '

   End Sub

#End Region

#Region " Members "

   Private mblnErrorProviderVisible As Boolean
   Private mbytNumberDecimals As Byte
   Private mbytNumberDigits As Byte
   Private mdecDefaultValue As Decimal
   Private mdecValueMax As Decimal
   Private mdecValueMin As Decimal
   Private mintErrorLanguage As enuLangueMessage
   Private mstrDisplayFormat As String

   Public Event ValidationError(ByVal sender As Object, ByVal e As NumericTBEventArgs)

   Enum enuErrors
      ErrNone
      ErrTooManyMinusSign
      ErrMinusSignMisplaced
      ErrNegativeNotAllowed
      ErrTooManyDot
      ErrDotNotAllowed
      ErrLessThenMin
      ErrGreaterThenMax
      ErrInvalidValue
      ErrInvalidChar
      ErrEmptyValue
      ErrTooManyDigits
      ErrTooManyDecimals
      ErrCannotApplyFormat
      ErrPasteCanceled
   End Enum

   Enum enuLangueMessage
      English
      Francais
   End Enum
#End Region '-- Members

#Region " Methods "

   Protected Overrides Sub CreateHandle()
      Me.Text = mdecDefaultValue.ToString
      MyBase.CreateHandle()
   End Sub

#Region " Public methods "

   '=====================================================================================
   '=== Returns wheter the textbox content is valid or not
   '=====================================================================================
   Public Function IsValid() As Boolean
      Return Me.ValidateFieldContent( _
         Decimal.Parse(Me.Text, Globalization.NumberStyles.Any).ToString)
   End Function

#End Region '-- Public methods

#Region " Protected methods "
   <System.Security.Permissions.PermissionSetAttribute( _
      System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
      Protected Overrides Sub WndProc(ByRef m As Message)

      Const WM_PASTE As Integer = &H302

      ' Listen for operating system messages
      Select Case m.Msg
         Case WM_PASTE
            Dim iData As IDataObject = Clipboard.GetDataObject()
            Dim s As String = CType(iData.GetData(DataFormats.Text), String)

            If Not s = Nothing Then
               Dim strNewResult As String
               Dim strBeginning As String = Me.Text.Substring(0, Me.SelectionStart)
               Dim strEnding As String = Me.Text.Substring(Me.SelectionStart _
                  + Me.SelectionLength)
               strNewResult = strBeginning & s & strEnding

               If Me.ValidateFieldContent(strNewResult) Then
                  'OK - Resulting field will be OK
                  MyBase.WndProc(m)
               Else
                  'The result of the paste would cause and invalid value so stop it
                  SetError(enuErrors.ErrPasteCanceled, strNewResult)
               End If
            End If
         Case Else
            MyBase.WndProc(m)
      End Select
   End Sub

#End Region '-- Protected methods

#Region " Privates methods "

   '=====================================================================================
   '=== Calculates the number of a given character into a string
   '=====================================================================================
   Private Function CountChar(ByVal pstrSource As String, ByVal pstrChar As String) As Integer
      Return pstrSource.Length - pstrSource.Replace(pstrChar, "").Length
   End Function

   '=====================================================================================
   '=== Custom initialization for the component
   '=====================================================================================
   Private Sub CustomInitialization()
      Me.DisplayFormat = "###,##0.00"
      Me.ErrorMessageLanguage = enuLangueMessage.Francais
      Me.NumberDecimals = 2
      Me.NumberDigits = 6
      Me.ValueMax = 999999.99D
      Me.ValueMin = -999999.99D
   End Sub

   '=====================================================================================
   '=== A centralized method to set the ErrorProvider control and to raise a custom event
   '=====================================================================================
   Private Sub SetError(ByVal pError As enuErrors, Optional ByVal pstrValue As String = "")
      Dim strMessageE As String
      Dim strMessageF As String

      Select Case pError
         Case enuErrors.ErrNone
            strMessageE = ""
            strMessageF = ""
         Case enuErrors.ErrEmptyValue
            strMessageE = "Field cannot be left empty!"
            strMessageF = "La valeur ne peut pas être laissé vide!"
         Case enuErrors.ErrTooManyMinusSign
            strMessageE = "Only one minus sign is allowed!"
            strMessageF = "Un seul symbole négatif est permis!"
         Case enuErrors.ErrMinusSignMisplaced
            strMessageE = "The minus sign must be placed at the beginning!"
            strMessageF = "Le symbole négatif doit être placé au début!"
         Case enuErrors.ErrTooManyDot
            strMessageE = "Only one decimal separator is allowed!"
            strMessageF = "Un seul séparateur de décimales est permis!"
         Case enuErrors.ErrDotNotAllowed
            strMessageE = "Decimal separator is not allowed!"
            strMessageF = "Le séparateur de décimal n'est pas permis!"
         Case enuErrors.ErrTooManyDigits
            strMessageE = "Too many digits! Only " & Me.NumberDigits.ToString _
               & " allowed."
            strMessageF = "Trop de chiffres! Seulement " & Me.NumberDigits.ToString _
               & " sont permis."
         Case enuErrors.ErrTooManyDecimals
            strMessageE = "Too many decimals! Only " & Me.NumberDecimals.ToString _
               & " allowed."
            strMessageF = "Trop de décimales! Seulement " & Me.NumberDecimals.ToString _
               & " sont permis."
         Case enuErrors.ErrLessThenMin
            strMessageE = "Value is less then the minimum allowed (" _
               & Me.ValueMin.ToString & ")!"
            strMessageF = "La valeur est inférieure au minimum permis (" _
               & Me.ValueMin.ToString & ")!"
         Case enuErrors.ErrGreaterThenMax
            strMessageE = "Value is greater then the maximum allowed (" _
               & Me.ValueMax.ToString & ")!"
            strMessageF = "La valeur est supérieure au maximum permis (" _
               & Me.ValueMax.ToString & ")!"
         Case enuErrors.ErrNegativeNotAllowed
            strMessageE = "Negative Values not allowed!"
            strMessageF = "Les valeurs négatives ne sont pas permises!"
         Case enuErrors.ErrInvalidValue
            strMessageE = "The field does not allow this value! (" & pstrValue & ")"
            strMessageF = "Valeur invalide! (" & pstrValue & ")"
         Case enuErrors.ErrInvalidChar
            strMessageE = "Character not allowed!"
            strMessageF = "Caractère invalide!"
         Case enuErrors.ErrCannotApplyFormat
            strMessageE = "Cannot apply the display format!"
            strMessageF = "Impossible d'appliquer la propriété DisplayFormat!"
         Case enuErrors.ErrPasteCanceled
            strMessageE = "The paste operation was canceled because it would result " _
               & "in an invalid value (" & pstrValue & ")!"
            strMessageF = "L'opération >Coller< a été annulé parce qu'elle causerait " _
               & "une valeur invalide (" & pstrValue & ")!"
         Case Else
            strMessageE = "Unkown error!"
            strMessageF = "Erreur inconnue!"
      End Select

      If ErrorMessageLanguage = enuLangueMessage.English Then
         If mblnErrorProviderVisible Then ErrorProvider1.SetError(Me, strMessageE)
         If strMessageE.Length > 0 Then
            RaiseEvent ValidationError(Me, New NumericTBEventArgs(strMessageE, Me.Text))
         End If
      Else
         If mblnErrorProviderVisible Then ErrorProvider1.SetError(Me, strMessageF)
         If strMessageF.Length > 0 Then
            RaiseEvent ValidationError(Me, New NumericTBEventArgs(strMessageF, Me.Text))
         End If
      End If
   End Sub

   '=====================================================================================
   '=== Validates many patters to be sure that the content of the field is valid.
   '=== Many of these validations cannot be done on the KeyPress event.
   '=== Others are also placed here to insure that paste or assignement is OK.
   '=====================================================================================
   Private Function ValidateFieldContent(ByVal pstrText As String) As Boolean
      SetError(enuErrors.ErrNone)

      'Empty string not allowed
      If pstrText.Length = 0 Then
         SetError(enuErrors.ErrEmptyValue)
         Return False
      End If

      'Invalid string
      If Not Microsoft.VisualBasic.IsNumeric(pstrText) Then      'TODO replace the IsNumeric
         SetError(enuErrors.ErrInvalidValue)
         Return False
      Else
         'E.Moreau 2003/10/26 
         'Quand bindé sur un DECIMAL il retourne une valeur du style 123456.1200 ce qui 
         'cause une erreur si le champ ne peut contenir que 2 décimales!
         pstrText = Microsoft.VisualBasic.Val(pstrText).ToString        'TODO replace the VAL
      End If

      'Check to see the number of minus sign(-) and its position
      Select Case CountChar(pstrText, "-")
         Case 0
            'OK No problems
         Case 1
            If Not pstrText.StartsWith("-") Then
               SetError(enuErrors.ErrMinusSignMisplaced)
               Return False
            End If
         Case Else
            SetError(enuErrors.ErrTooManyMinusSign)
            Return False
      End Select

      'Check to see if there is only one decimal separator
      Select Case CountChar(pstrText, _
         System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)
         Case 0
            'OK, No problems
         Case 1
            Dim intPos As Integer = pstrText.Replace("-", "").IndexOf _
                     (System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)

            'Check if the number of digits to the left of the decimal separator is OK
            If intPos > Me.NumberDigits Then
               SetError(enuErrors.ErrTooManyDigits)
               Return False
            End If

            'Check if the number of digits to the right of the decimal separator is OK
            If pstrText.Replace("-", "").Length - (intPos + 1) > Me.NumberDecimals Then
               SetError(enuErrors.ErrTooManyDecimals)
               Return False
            End If
         Case Else
            SetError(enuErrors.ErrTooManyDot)
            Return False
      End Select

      'Check min and max values
      If Me.ValueMin <> 0 Or Me.ValueMax <> 0 Then
         If Microsoft.VisualBasic.Val(pstrText) < Me.ValueMin Then    'TODO replace the VAL
            SetError(enuErrors.ErrLessThenMin)
            Return False
         End If
         If Microsoft.VisualBasic.Val(pstrText) > Me.ValueMax Then    'TODO replace the VAL
            SetError(enuErrors.ErrGreaterThenMax)
            Return False
         End If
      End If

      'If we get through here, the value should be OK!!!
      Return True
   End Function

   '=====================================================================================
   '=== Validates a single character (called by the KeyPress event).
   '=====================================================================================
   Private Function ValidateKey() As Boolean
      Dim intPos As Integer = Me.Text.IndexOf _
            (System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator)

      If intPos = -1 Then
         If Me.Text.Replace("-", "").Length = Me.NumberDigits Then
            SetError(enuErrors.ErrTooManyDigits)
            Return False
         End If
      Else
         If Me.SelectionStart > intPos Then
            'Check if the number of digits to the right of the decimal separator is OK
            If Me.Text.Length - (intPos + 1) >= Me.NumberDecimals Then
               SetError(enuErrors.ErrTooManyDecimals)
               Return False
            End If
         Else
            'Check if the number of digits to the left of the decimal separator is OK
            If Me.Text.IndexOf("-") = -1 Then
               If intPos >= Me.NumberDigits Then
                  SetError(enuErrors.ErrTooManyDigits)
                  Return False
               End If
            Else
               If intPos - 1 > Me.NumberDigits Then
                  SetError(enuErrors.ErrTooManyDigits)
                  Return False
               End If
            End If
         End If
      End If

      'If we get through here, the value should be OK!!!
      Return True
   End Function

#End Region '-- Privates methods

#End Region    '-- Methods 

#Region " Subclassed events "

   Private Sub SCEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Enter
      Try
         'Remove formatting characters
         MyBase.Text = Decimal.Parse(Me.Text, Globalization.NumberStyles.Any).ToString
      Catch
         'Nothing, just don't do it!!!
      End Try
      Me.SelectAll()
   End Sub

   Private Sub SCKeyPress( _
      ByVal eventSender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) _
      Handles MyBase.KeyPress

      Dim KeyAscii As Integer = Convert.ToInt32(e.KeyChar)

      If KeyAscii = 8 Then
         '=====================================================================================
         '=== BackSpace
         '=====================================================================================
         'Let it do its job

      ElseIf KeyAscii = 3 Then
         '=====================================================================================
         '=== CTRL-C
         '=====================================================================================
         'Let it pass, validation will be done into the TextChanged event

      ElseIf KeyAscii = 22 Then
         '=====================================================================================
         '=== CTRL-V
         '=====================================================================================
         'Let it pass, validation will be done into the WndProc method

      ElseIf KeyAscii = 26 Then
         '=====================================================================================
         '=== CTRL-Z
         '=====================================================================================
         'Let it pass

      ElseIf e.KeyChar _
         = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator Then

         '=====================================================================================
         '=== Validation for .
         '=====================================================================================
         'E.Moreau 2003.11.02 - remove the selected text from the validation
         Dim strText As String
         If Me.SelectionLength > 0 Then
            strtext = Me.Text.Replace(Me.SelectedText, "")
         Else
            strtext = Me.Text
         End If

         ' if we already have a period, throw it away
         If strText.IndexOf(".") >= 0 Then
            SetError(enuErrors.ErrTooManyDot)
            KeyAscii = 0
         End If

         ' if we don't have decimals, throw it away
         If Me.NumberDecimals = 0 Then
            SetError(enuErrors.ErrDotNotAllowed)
            KeyAscii = 0
         End If

      ElseIf e.KeyChar = "-" Then
         '=====================================================================================
         '=== Validation for -
         '=====================================================================================
         'E.Moreau 2003.11.02 - remove the selected text from the validation
         Dim strText As String
         If Me.SelectionLength > 0 Then
            strtext = Me.Text.Replace(Me.SelectedText, "")
         Else
            strtext = Me.Text
         End If

         ' The number can only have one minus sign, so 
         ' if we already have one, throw this one away
         If strText.IndexOf("-") >= 0 Then
            SetError(enuErrors.ErrTooManyMinusSign)
            KeyAscii = 0
         End If

         ' if the insertion point is not sitting at zero
         ' (which is the beginning of the field), 
         ' throw away the minus sign (because it's not
         ' valid except in first position)
         If Me.SelectionStart <> 0 Then
            SetError(enuErrors.ErrMinusSignMisplaced)
            KeyAscii = 0
         End If

         ' do we allow negative numbers?
         If Me.ValueMin >= 0 Then
            SetError(enuErrors.ErrNegativeNotAllowed)
            KeyAscii = 0
         End If

      ElseIf e.KeyChar >= "0" And e.KeyChar <= "9" Then
         '=====================================================================================
         '=== Validation for numbers
         '=====================================================================================
         If Not ValidateKey() Then
            'SetError(enuErrors.ErrInvalidChar)
            KeyAscii = 0
         End If

      Else
         SetError(enuErrors.ErrInvalidChar)
         KeyAscii = 0
      End If

      If KeyAscii = 0 Then
         e.Handled = True
      End If
   End Sub

   Private Sub SCLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Leave
      Try
         Me.Text = CType(Me.Text, Decimal).ToString(Me.DisplayFormat, Nothing)
      Catch
         SetError(enuErrors.ErrCannotApplyFormat)
      Finally
         If Me.Text.Length = 0 Then
            Me.Text = mdecDefaultValue.ToString(Me.DisplayFormat, Nothing)
         End If
      End Try
   End Sub

#End Region '-- Subclassed events 

#Region " Exposed Properties "

#Region " Overrides "
   Public Overrides Property Text() As String
      Get
         Return MyBase.Text
      End Get
      Set(ByVal Value As String)
         If Value Is Nothing Then Value = mdecDefaultValue.ToString
         If Me.ValidateFieldContent( _
            Decimal.Parse(Value, Globalization.NumberStyles.Any).ToString) Then

            'MyBase.Text = Value
            'E.Moreau 2003/10/26
            'Formater quand une valeur est donnée à la propriété TEXT
            MyBase.Text = CType(Value, Decimal).ToString(Me.DisplayFormat, Nothing)
         Else
            SetError(enuErrors.ErrInvalidValue, Value)
         End If
      End Set
   End Property
#End Region '-- Overrides

#Region " Custom "

   'This property contains the display format
   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("The default value (also the value when the control is left empty).")> _
      Public Property DefaultValue() As Decimal
      Get
         Return mdecDefaultValue
      End Get
      Set(ByVal Value As Decimal)
         mdecDefaultValue = Value
      End Set
   End Property

   'This property contains the display format
   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("The display format (passed to Decimal.ToString)")> _
      Public Property DisplayFormat() As String
      Get
         Return mstrDisplayFormat
      End Get
      Set(ByVal Value As String)
         mstrDisplayFormat = Value
      End Set
   End Property

   'This property dictates the language of error messages
   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("The language of error messages")> _
      Public Property ErrorMessageLanguage() As enuLangueMessage
      Get
         Return mintErrorLanguage
      End Get
      Set(ByVal Value As enuLangueMessage)
         mintErrorLanguage = Value
      End Set
   End Property

   'This property contains the number of digits (to the right of the decimal point)
   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("The number of digits (to the right of the decimal point)")> _
      Public Property NumberDecimals() As Byte
      Get
         Return mbytNumberDecimals
      End Get
      Set(ByVal Value As Byte)
         mbytNumberDecimals = Value
      End Set
   End Property

   'This property contains the maximum number of digits (decimals included)
   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("The maximum number of digits (decimals excluded)")> _
   Public Property NumberDigits() As Byte
      Get
         Return mbytNumberDigits
      End Get
      Set(ByVal Value As Byte)
         mbytNumberDigits = Value
      End Set
   End Property

   <CategoryAttribute("S2iNumericTextBox Properties"), _
    DescriptionAttribute("The maximum value the textbox can contain")> _
    Public Property ValueMax() As Decimal
      Get
         Return mdecValueMax
      End Get
      Set(ByVal Value As Decimal)
         mdecValueMax = Value
      End Set
   End Property

   <CategoryAttribute("S2iNumericTextBox Properties"), _
    DescriptionAttribute("The minimum value the textbox can contain")> _
    Public Property ValueMin() As Decimal
      Get
         Return mdecValueMin
      End Get
      Set(ByVal Value As Decimal)
         mdecValueMin = Value
      End Set
   End Property
#End Region '-- Custom

#Region " Error Provider "

   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("BlinkRate property of the Provider control.")> _
   Public Property ErrProviderBlinkRate() As Integer
      Get
         Return ErrorProvider1.BlinkRate
      End Get
      Set(ByVal Value As Integer)
         ErrorProvider1.BlinkRate = Value
      End Set
   End Property

   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("BlinkStyle property of the Provider control.")> _
   Public Property ErrProviderBlinkStyle() As ErrorBlinkStyle
      Get
         Return ErrorProvider1.BlinkStyle
      End Get
      Set(ByVal Value As ErrorBlinkStyle)
         ErrorProvider1.BlinkStyle = Value
      End Set
   End Property

   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("Icon property of the Provider control.")> _
   Public Property ErrProviderIcon() As Icon
      Get
         Return ErrorProvider1.Icon
      End Get
      Set(ByVal Value As Icon)
         ErrorProvider1.Icon = Value
      End Set
   End Property

   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("IconAlignment property of the Provider control.")> _
   Public Property ErrProviderIconAlignment() As ErrorIconAlignment
      Get
         Return ErrorProvider1.GetIconAlignment(Me)
      End Get
      Set(ByVal Value As ErrorIconAlignment)
         ErrorProvider1.SetIconAlignment(Me, Value)
      End Set
   End Property

   <CategoryAttribute("S2iNumericTextBox Properties"), _
      DescriptionAttribute("Will the Error Provider control be visible?")> _
   Public Property ErrProviderVisible() As Boolean
      Get
         Return mblnErrorProviderVisible
      End Get
      Set(ByVal Value As Boolean)
         mblnErrorProviderVisible = Value
      End Set
   End Property
#End Region '-- Error Provider 

#End Region '-- Exposed Properties

End Class


' NumericTBEventArgs: a custom event inherited from EventArgs.
Public Class NumericTBEventArgs
   Inherits EventArgs

   Public Sub New(ByVal pMessage As String, ByVal pValue As String)
      Me.Message = pMessage
      Me.Value = pValue
   End Sub

   Public Message As String
   Public Value As String
End Class
'end of class NumericTBEventArgs

from a solution provided by Eric Moreau in Message #992747

Automating Word Mail Merge Functionality Into .NET
Here is sample code on how to provide Word Mail Merge capabilities inside of .NET:
(Important: Make sure to add OPTION STRICT OFF at the top of the code window)


 Private Sub InsertLines(ByVal LineNum As Integer, ByRef objSelection As Object)
      Dim iCount As Integer

      ' Insert "LineNum" blank lines.
      For iCount = 1 To LineNum
         objSelection.TypeParagraph()
      Next iCount
   End Sub


   Private Sub FillRow(ByVal Doc As Object, ByVal Row As Integer, _
   ByVal Text1 As String, ByVal Text2 As String, _
   ByVal Text3 As String, ByVal Text4 As String)

      With Doc.Tables.Item(1)
         ' Insert the data in the specific cell.
         .Cell(Row, 1).Range.InsertAfter(Text1)
         .Cell(Row, 2).Range.InsertAfter(Text2)
         .Cell(Row, 3).Range.InsertAfter(Text3)
         .Cell(Row, 4).Range.InsertAfter(Text4)
      End With
   End Sub


   Private Sub CreateMailMergeDataFile( _
      ByRef objApp As Object, ByRef objDocs As Object, _
      ByRef objDoc As Object, ByRef objMailMerge As Object)

      Dim wrdDataDoc As Object
      Dim iCount As Integer

      ' Create a data source at C:\DataDoc.doc containing the field data.
      objMailMerge.CreateDataSource(Name:="C:\DataDoc.doc", _
           HeaderRecord:="FirstName, LastName, Address, CityStateZip")
      ' Open the file to insert data.
      wrdDataDoc = objDocs.Open("C:\DataDoc.doc")
      For iCount = 1 To 2
         wrdDataDoc.Tables.Item(1).Rows.Add()
      Next iCount
      ' Fill in the data.
      FillRow(wrdDataDoc, 2, "Steve", "DeBroux", _
           "4567 Main Street", "Buffalo, NY  98052")
      FillRow(wrdDataDoc, 3, "Jan", "Miksovsky", _
           "1234 5th Street", "Charlotte, NC  98765")
      FillRow(wrdDataDoc, 4, "Brian", "Valentine", _
           "12348 78th Street  Apt. 214", "Lubbock, TX  25874")
      ' Save and close the file.
      wrdDataDoc.Save()
      wrdDataDoc.Close(False)
   End Sub


   Private Sub DoTheMerge()
      Dim objApp As Object
      Dim objDocs As Object
      Dim objDoc As Object
      Dim objDataDoc As Object

      Dim objSelection As Object
      Dim objMailMerge As Object
      Dim objMergeFields As Object
      Dim objDestination As Object
      'Dim objParagraph As Object
      'Dim objPara As Object
      Dim objRange As Object

      objApp = CreateObject("Word.Application")
      objApp.visible = True
      objDocs = objApp.Documents

      Try
         Dim StrToAdd As String
         ' Add a new document.
         objDoc = objDocs.Add()
         objDoc.Select()

         objSelection = objApp.Selection
         objRange = objSelection.range

         objMailMerge = objDoc.MailMerge
         objDestination = objMailMerge.Destination
         objMergeFields = objMailMerge.fields()

         objDoc.select()

         ' Create MailMerge Data file.
         CreateMailMergeDataFile(objApp, objDocs, objDoc, objMailMerge)

         ' Create a string and insert it in the document.
         StrToAdd = "State University" & vbCr & _
                  "Electrical Engineering Department"

         objSelection.ParagraphFormat.Alignment = _
                   Word.WdParagraphAlignment.wdAlignParagraphCenter

         objSelection.TypeText(StrToAdd)

         InsertLines(4, objSelection)

         ' Insert merge data.
         objSelection.ParagraphFormat.Alignment = _
                  Word.WdParagraphAlignment.wdAlignParagraphLeft


         objRange = objSelection.range
         objMergeFields.Add(objRange, "FirstName")
         objSelection.TypeText(" ")
         objRange = objSelection.range
         objMergeFields.Add(objRange, "LastName")
         objRange = objSelection.range
         objSelection.TypeParagraph()

         objRange = objSelection.range
         objMergeFields.Add(objRange, "Address")
         objSelection.TypeParagraph()
         objRange = objSelection.range
         objMergeFields.Add(objRange, "CityStateZip")


         InsertLines(2, objSelection)

         ' Right justify the line and insert a date field
         ' with the current date.
         objSelection.ParagraphFormat.Alignment = _
               Word.WdParagraphAlignment.wdAlignParagraphRight
         objSelection.InsertDateTime( _
              DateTimeFormat:="dddd, MMMM dd, yyyy", _
              InsertAsField:=False)


         InsertLines(2, objSelection)

         ' Justify the rest of the document.
         objSelection.ParagraphFormat.Alignment = _
               Word.WdParagraphAlignment.wdAlignParagraphJustify

         objSelection.TypeText("Dear ")
         objRange = objSelection.range
         objMergeFields.Add(objRange, "FirstName")
         'objDoc.select()
         objSelection.TypeText(",")

         InsertLines(2, objSelection)


         ' Create a string and insert it into the document.
         StrToAdd = "Thank you for your recent request for next " & _
            "semester's class schedule for the Electrical " & _
            "Engineering Department. Enclosed with this " & _
            "letter is a booklet containing all the classes " & _
            "offered next semester at State University.  " & _
            "Several new classes will be offered in the " & _
            "Electrical Engineering Department next semester.  " & _
            "These classes are listed below."
         objSelection.TypeText(StrToAdd)

         InsertLines(2, objSelection)

         ' Insert a new table with 9 rows and 4 columns.
         objRange = objSelection.range
         objDoc.Tables.Add(objRange, NumRows:=9, _
             NumColumns:=4)

         With objDoc.Tables.Item(1)
            ' Set the column widths.
            .Columns.Item(1).SetWidth(51, Word.WdRulerStyle.wdAdjustNone)
            .Columns.Item(2).SetWidth(170, Word.WdRulerStyle.wdAdjustNone)
            .Columns.Item(3).SetWidth(100, Word.WdRulerStyle.wdAdjustNone)
            .Columns.Item(4).SetWidth(111, Word.WdRulerStyle.wdAdjustNone)
            ' Set the shading on the first row to light gray.
            .Rows.Item(1).Cells.Shading.BackgroundPatternColorIndex = _
             Word.WdColorIndex.wdGray25
            ' Bold the first row.
            .Rows.Item(1).Range.Bold = True
            ' Center the text in Cell (1,1).
            .Cell(1, 1).Range.Paragraphs.Alignment = _
                    Word.WdParagraphAlignment.wdAlignParagraphCenter

            ' Fill each row of the table with data.
            FillRow(objDoc, 1, "Class Number", "Class Name", "Class Time", _
               "Instructor")
            FillRow(objDoc, 2, "EE220", "Introduction to Electronics II", _
                    "1:00-2:00 M,W,F", "Dr. Jensen")
            FillRow(objDoc, 3, "EE230", "Electromagnetic Field Theory I", _
                    "10:00-11:30 T,T", "Dr. Crump")
            FillRow(objDoc, 4, "EE300", "Feedback Control Systems", _
                    "9:00-10:00 M,W,F", "Dr. Murdy")
            FillRow(objDoc, 5, "EE325", "Advanced Digital Design", _
                    "9:00-10:30 T,T", "Dr. Alley")
            FillRow(objDoc, 6, "EE350", "Advanced Communication Systems", _
                    "9:00-10:30 T,T", "Dr. Taylor")
            FillRow(objDoc, 7, "EE400", "Advanced Microwave Theory", _
                    "1:00-2:30 T,T", "Dr. Lee")
            FillRow(objDoc, 8, "EE450", "Plasma Theory", _
                    "1:00-2:00 M,W,F", "Dr. Davis")
            FillRow(objDoc, 9, "EE500", "Principles of VLSI Design", _
                    "3:00-4:00 M,W,F", "Dr. Ellison")
         End With

         ' Go to the end of the document.
         objApp.Selection.GoTo(Word.WdGoToItem.wdGoToLine, _
          Word.WdGoToDirection.wdGoToLast)

         InsertLines(2, objSelection)

         ' Create a string and insert it into the document.
         StrToAdd = "For additional information regarding the " & _
                  "Department of Electrical Engineering, " & _
                  "you can visit our Web site at "
         objSelection.TypeText(StrToAdd)
         ' Insert a hyperlink to the Web page.
         objRange = objSelection.range
         objSelection.Hyperlinks.Add(Anchor:=objRange, _
            Address:="http://www.ee.stateu.tld")
         ' Create a string and insert it in the document.
         StrToAdd = ".  Thank you for your interest in the classes " & _
                  "offered in the Department of Electrical " & _
                  "Engineering.  If you have any other questions, " & _
                  "please feel free to give us a call at " & _
                  "555-1212." & vbCr & vbCr & _
                  "Sincerely," & vbCr & vbCr & _
                  "Kathryn M. Hinsch" & vbCr & _
                  "Department of Electrical Engineering" & vbCr
         objSelection.TypeText(StrToAdd)

         ' Perform mail merge.
         objMailMerge.Destination = _
                  Word.WdMailMergeDestination.wdSendToNewDocument

         objMailMerge.Execute(False)

         ' Close the original form document.
         objDoc.Saved = True
         objDoc.Close(False)

         ' Release References.
         objSelection = Nothing
         objMailMerge = Nothing
         objMergeFields = Nothing
         objDoc = Nothing
         objApp = Nothing

         ' Clean up temp file.
         System.IO.File.Delete("C:\DataDoc.doc")

         Me.txtResults.Text = "No program Errors occurred !"

      Catch ex As Exception
         Dim strErr As String = ex.Message & vbCrLf & vbCrLf
         strErr += "Error Stack:" & vbCrLf
         strErr += ex.StackTrace
         Me.txtResults.Text = strErr
      End Try

   End Sub

   Private Sub btnButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
      Handles btnButton1.Click
      DoTheMerge()
   End Sub

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

   End Sub

from a solution provided by Allan Williams in Message #992701

Working With CSV File
Here is a class that allows you to save to / read from a comma-delimited file (CSV):
To read the contents of a CSV file:

CSVDataAdapter CSVda = new CSVDataAdapter(@"c:\MyFile.csv");
CSVda.HasHeaderRow = true;
DataSet ds = new DataSet();
CSVda.Fill(ds);




To write to a CSV file:

CSVDataAdapter CSVda = new CSVDataAdapter(@"c:\MyFile.csv");
bool InclHeader = true;
CSVda.Update(MyDataSet,"MyTable",InclHeader);


Here is the class code for CSVDataAdapter that originated from the OpenNetCF site:

using System;
using System.Collections;
using System.IO;
using System.Data;

namespace MyNameSpace
{
   /// <summary>
   /// Supports the reading and writing of Comma separated Values into a DataSet
   /// </summary>
   public class CSVDataAdapter : System.Data.IDataAdapter
   {
      #region Fields

      //name of CSV file
      private string m_filename;

      //tablename
      private string m_tablename;

      //stream reader
      private StreamReader m_reader;

      //stream writer (for updates)
      private StreamWriter m_writer;

      //file contains header row?
      private bool m_hasheader;
      
      //store header names (if applicable)
      private string[] m_headers;

      #endregion
      
      #region Constructor
      /// <summary>
      /// Creates a new instance of the CSVDataAdapter class
      /// </summary>
      /// <param name="filename">Filename of a valid CSV data file.</param>
      /// <param name="hasHeader">True if first row is a header row naming the columns 
      /// contained in the data, False if first row is a data row.</param>
      public CSVDataAdapter(string filename, bool hasHeader)
      {
         //set filename
         m_filename = filename;

         System.IO.FileInfo fi = new FileInfo(m_filename);

         //tablename is filename without path and extension
         m_tablename = fi.Name.Replace("." + fi.Extension ,"");
      
         //set whether file contains a header row with column names
         m_hasheader = hasHeader;
      }
      /// <summary>
      /// Creates a new instance of the CSVDataAdapter class from a file with no header row.
      /// </summary>
      /// <param name="filename">Filename of a valid CSV data file.</param>
      public CSVDataAdapter(string filename) : this(filename, false){}
      #endregion

      #region Properties

      #region FileName
      /// <summary>
      /// Full path to the CSV file name
      /// </summary>
      public string FileName
      {
         get
         {
            return m_filename;
         }
         set
         {
            m_filename = value;
         }
      }
      #endregion

      #region Header Row
      /// <summary>
      /// Flag indicating if first row of files indicates column headers for the table.
      /// </summary>
      /// <value>
      /// True if first row of file contains column headers, else False (Default is False).
      /// </value>
      public bool HasHeaderRow
      {
         get
         {
            return m_hasheader;
         }
         set
         {
            m_hasheader = value;
         }
      }
      #endregion

      #endregion

      #region IDataAdapter Members

      #region Fill
      /// <summary>
      /// Adds or refreshes rows in the DataSet to match those in the data source
      /// </summary>
      /// <param name="dataSet">A DataSet to fill with records and, if necessary, schema.</param>
      /// <returns>The number of rows successfully added to or refreshed in the DataSet.
      /// This does not include rows affected by statements that do not return rows.</returns>
      public int Fill(System.Data.DataSet dataSet)
      {
         //fill with default table name
         return Fill(dataSet, m_tablename);
      }
      /// <summary>
      /// using the DataSet and DataTable names.
      /// </summary>
      /// <param name="dataSet">A DataSet to fill with records and, if necessary, schema.</param>
      /// <param name="tableName">The name of the source table to use for table mapping.</param>
      /// <returns>The number of rows successfully added to or refreshed in the DataSet. 
      /// This does not include rows affected by statements that do not return rows.</returns>
      public int Fill(System.Data.DataSet dataSet, string tableName)
      {
         //table within the dataset
         DataTable dt = dataSet.Tables.Add(tableName);

         //store records affected
         int records = 0;

         //raw row
         string rawrow;

         //store the current row
         string[] rowbuffer = new string[0];

         //more records
         bool morerecords = true;

         //open stream to read from file
         m_reader = new StreamReader(m_filename);

         if(m_hasheader)
         {
            //read header row and construct schema
            m_headers = SplitRow(m_reader.ReadLine());

            foreach(string column in m_headers)
            {
               //add to columns collection
               DataColumn dc = dt.Columns.Add(column);
               dc.DataType = typeof(string);
               dc.AllowDBNull = true;
            }

            //read first data row
            rawrow = m_reader.ReadLine();

            //check for null first - avoid throwing exception
            if(rawrow==null | rawrow==String.Empty)
            {
               morerecords = false;
            }
            else
            {
               rowbuffer = SplitRow(rawrow);
            }
         }
         else
         {
            //read line
            rawrow = m_reader.ReadLine();

            if(rawrow==null | rawrow==String.Empty)
            {
               morerecords = false;
            }
            else
            {
               //read the first row and get the length
               rowbuffer = SplitRow(rawrow);
            }
            

            for(int iColumn = 0; iColumn < rowbuffer.Length; iColumn++)
            {
               //add to columns collection
               DataColumn dc = dt.Columns.Add("Column " + iColumn.ToString());
               dc.DataType = typeof(string);
               dc.AllowDBNull = true;
            }
         }

         //processing of further rows goes here
         while(morerecords)
         {
            //increment rows affected
            records++;

            //add values to row and insert into table
            dt.Rows.Add(rowbuffer);

            //read the next row
            rawrow = m_reader.ReadLine();

            if(rawrow==null | rawrow==String.Empty)
            {
               morerecords = false;
            }
            else
            {
               //read the first row and get the length
               rowbuffer = SplitRow(rawrow);
            }
         }

         //close stream
         m_reader.Close();

         //mark dataset as up-to-date
         dataSet.AcceptChanges();

         return records;
      }
      #endregion

      #region Interface Methods

      /// <summary>
      /// Not Supported
      /// </summary>
      System.Data.ITableMappingCollection System.Data.IDataAdapter.TableMappings
      {
         get
         {
            // TODO: Add CSVDataAdapter.TableMappings getter implementation
            return null;
         }
      }

      /// <summary>
      /// Not Supported
      /// </summary>
      System.Data.MissingSchemaAction System.Data.IDataAdapter.MissingSchemaAction
      {
         get
         {
            return MissingSchemaAction.Add;
         }
         set
         {
            // TODO: Add CSVDataAdapter.MissingSchemaAction setter implementation
         }
      }

      /// <summary>
      /// Not Supported
      /// </summary>
      System.Data.MissingMappingAction System.Data.IDataAdapter.MissingMappingAction
      {
         get
         {
            return System.Data.MissingMappingAction.Passthrough;
         }
         set
         {
            // TODO: Add CSVDataAdapter.MissingMappingAction setter implementation
         }
      }

      /// <summary>
      /// Not Supported
      /// </summary>
      /// <returns></returns>
      System.Data.IDataParameter[] System.Data.IDataAdapter.GetFillParameters()
      {
         // TODO: Add CSVDataAdapter.GetFillParameters implementation
         return null;
      }

      /// <summary>
      /// Not Supported
      /// </summary>
      /// <param name="dataSet"></param>
      /// <param name="schemaType"></param>
      /// <returns></returns>
      System.Data.DataTable[] System.Data.IDataAdapter.FillSchema( 
         System.Data.DataSet dataSet, System.Data.SchemaType schemaType)
      {
         // TODO: Add CSVDataAdapter.FillSchema implementation
         return null;
      }

      #endregion

      #region Update
      /// <summary>
      /// Writes out the updated DataSet contents to CSV File.
      /// </summary>
      /// <param name="dataSet">The DataSet used to update the data source.</param>
      /// <returns>The number of rows successfully updated from the DataSet.</returns>
      public int Update(System.Data.DataSet dataSet)
      {
         //update default tablename
         return Update(dataSet, m_tablename);
      }
      /// <summary>
      /// Writes out the updated named DataTable from the DataSet to CSV File.
      /// </summary>
      /// <param name="dataSet">The DataSet used to update the data source.</param>
      /// <param name="srcTable">The DataTable.Name to be written.</param>
      /// <returns>The number of rows successfully updated from the DataSet.</returns>
      public int Update(System.Data.DataSet dataSet, string srcTable)
      {
         return Update(dataSet,srcTable,false);
      }

      public int Update(System.Data.DataSet dataSet, string srcTable, bool inclHeader)
      {
         if (inclHeader)
         {
            m_hasheader = true;
         }

         if(dataSet.HasChanges())
         {
            DataTable table;

            try
            {
               table = dataSet.Tables[srcTable];
            }
            catch
            {
               //could not find the table specified
               throw new ArgumentException("srcTable does not exist in specified dataSet");
            }
            //open filestream (overwrite previous file)
            m_writer = new StreamWriter(m_filename, false);

            if(m_hasheader)
            {
               string columnrow = "";

               //write header row
               foreach(DataColumn dc in table.Columns)
               {
                  //write column name
                  columnrow += dc.ColumnName + ",";
               }

               //write assembled column names minus the trailing comma
               m_writer.WriteLine(columnrow.TrimEnd(','));
            }

            //count the number of rows written
            int rowsaffected = 0;

            //write out all the rows (unless they were deleted)
            foreach(DataRow thisrow in table.Rows)
            {
               //write all except deleted rows
               if(thisrow.RowState!=DataRowState.Deleted)
               {
                  //write assembled row minus the trailing comma
                  m_writer.WriteLine(BuildRow(thisrow.ItemArray));

                  rowsaffected ++;
               }
            }

            //close filestream
            m_writer.Close();
            
            //mark dataset as up-to-date
            try
            {
               dataSet.AcceptChanges();
            }
            catch
            {
            }


            //return number of rows written
            return rowsaffected;
         }
         else
         {
            //no changes - ignore
            return 0;
         }
      }

      #endregion

      #endregion

      #region Helper Functions

      #region Quote String
      /// <summary>
      /// Add quotes to a string if it contains a space or carriage return
      /// </summary>
      /// <param name="inString"></param>
      /// <returns></returns>
      private static string QuoteString(object inString)
      {
         if(inString.ToString().IndexOf(' ') > -1 || inString.ToString().IndexOf(',') > -1)
         {
            return "\"" + inString.ToString() + "\"";
         }
         else
         {
            return inString.ToString();
         }
      }
      #endregion

      #region Build Row
      /// <summary>
      /// Builds a row into a single string with delimiting characters
      /// </summary>
      /// <returns></returns>
      private static string BuildRow(object[] values)
      {
         //create string for a single output row
         string row = "";

         //loop for each item in the row
         foreach(object column in values)
         {
            if(column != null)
            {
               //add the item (with quotes as appropriate
               row += QuoteString(column);
            }

            //add the delimiting character
            row += ",";
         }
         
         //remove the extra delimiter at the end
         row = row.Remove(row.Length - 1, 1);

         return row;
      }
      #endregion

      #region Split Row
      /// <summary>
      /// Splits a delimited row into an array of values
      /// </summary>
      /// <param name="row"></param>
      /// <returns></returns>
      private static string[] SplitRow(string row)
      {
         //basic splitting no special cases
         string[] segments = row.Split(',');
         //store the fixedup segments
         ArrayList parsedsegments = new ArrayList();
         bool iscontinuation = false;
         string buffer = "";

         for(int iSegment = 0; iSegment < segments.Length; iSegment++)
         {
            //if value begins with a quote
            if(segments[iSegment].StartsWith("\""))
            {
               //if value also ends with a quote
               if(segments[iSegment].EndsWith("\""))
               {
                  //string is unbroken quoted value
                  parsedsegments.Add(segments[iSegment].Trim('"'));
               }
               else
               {
                  //string is beginning of quoted value (which contained a comma)
                  buffer = segments[iSegment].TrimStart('"');
                  
                  //flag that following section(s) are part of this quoted string
                  iscontinuation = true;
               }
            }
            else
            {
               if(iscontinuation)
               {
                  if(segments[iSegment].EndsWith("\""))
                  {
                     //add buffer, comma and this last section with quotes removed
                     parsedsegments.Add(buffer + "," + segments[iSegment].TrimEnd('"'));
                     
                     //this is the end of a continuation
                     iscontinuation = false;
                  }
                  else
                  {
                     //add this section and continue
                     buffer += "," + segments[iSegment];
                  }
               }
               else
               {
                  //item is an unquoted value - add straight in
                  parsedsegments.Add(segments[iSegment]);
               }
            }
         }

         return (string[])parsedsegments.ToArray(typeof(string));
      }
      #endregion

      #endregion
   }
}

from a solution provided by Cathi Gero in Message #990930

More articles from this author

NoTitleDate
1.Cathi Gero's .NET TipsOctober 2003
2.Cathi Gero's .NET TipsNovember 2003
3.Cathi Gero's .NET TipsDecember 2003
4.Cathi Gero's .NET TipsJanuary 2004
5.Cathi Gero's .NET TipsFebruary 2004
6.Cathi Gero's .NET TipsMarch 2004
7.Cathi Gero's .NET TipsApril 2004
8.Cathi Gero's .NET TipsMay 2004
9.Cathi Gero's .NET TipsJune 2004
10.Cathi Gero's .NET TipsJuly 2004
11.Cathi Gero's .NET TipsAugust 2004
12.Cathi Gero's .NET TipsSeptember 2004
13.Cathi Gero's .NET TipsOctober 2004
14.Cathi Gero's .NET TipsNovember 2004
15.Cathi Gero's .NET TipsDecember 2004
16.Cathi Gero's .NET TipsJanuary 2005
17.Cathi Gero's .NET TipsFebruary 2005
18.Cathi Gero's .NET TipsMarch 2005
19.Cathi Gero's .NET TipsApril 2005
20.Cathi Gero's .NET TipsJune 2005
21.Cathi Gero's .NET TipsJuly 2005
22.Cathi Gero's .NET TipsAugust 2005
23.Cathi Gero's .NET TipsSeptember 2003
24.Cathi Gero's .NET TipsAugust 2003
25.Cathi Gero's .NET TipsJuly 2003
26.Cathi Gero's .NET TipsJune 2003
27.Cathi Gero's .NET TipsFebruary 2003
28.Cathi Gero's .NET TipsJanuary 2003
29.Cathi Gero's .NET TipsMarch 2003
30.Cathi Gero's .NET TipsMay 2003
31.Cathi Gero's .NET TipsApril 2003
32.Cathi Gero's .NET TipsDecember 2002
33.Cathi Gero's .NET TipsNovember 2002
34.Cathi Gero's .NET TipsOctober 2002

Copyright © 1993 - 2014 Level Extreme Inc., All Rights Reserved · Telephone: 506-783-9007 Email: info@universalthread.com · Privacy & Security · Copyright · Terms & Conditions