简体   繁体   中英

Visual Studio Excel AddIn - VB.Net - Help Avoiding vb.Null Error with Range of Different Data

I am building an Excel Addin using Visual Studio and am having trouble translating my VBA code that works as an Excel macro to VB.Net code. One item I am stuck on is how to run a macro on a range of data that has different values without returning a vb.null error message. Is there a way to run the below code for numbers in a range that include two of the below number formats? I tried to make the logic so that if it returns a Null value (because of 2 number formats in a range), it skips to the final Else statement and makes all values #,##0.0_);(#,##0.0). Thank you!

Private Sub BtnNumberFormat_Click(sender As Object, e As RibbonControlEventArgs) Handles BtnNumberFormat.Click

    Dim ActiveWorksheet As Microsoft.Office.Interop.Excel.Worksheet =
        Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets(1)

    Dim Worksheet As Microsoft.Office.Tools.Excel.Worksheet =
        Globals.Factory.GetVstoObject(ActiveWorksheet)

    Dim Selection As Excel.Range = TryCast(Globals.ThisAddIn.Application.Selection, Excel.Range)

    If Selection IsNot Nothing Then
        ****If Not IsDBNull(Selection) Then****
            If Selection.NumberFormat = "#,##0.0_);(#,##0.0)" Then
                Selection.NumberFormat = "$#,##0.0_);($#,##0.0)"
            Else
                If Selection.NumberFormat = "$#,##0.0_);($#,##0.0)" Then
                    Selection.NumberFormat = "#,##0.0%_);(#,##0.0%)"
                Else
                    If Selection.NumberFormat = "#,##0.0%_);(#,##0.0%)" Then
                        Selection.NumberFormat = "#,##0.0x_)"
                    Else
                        If Selection.NumberFormat = "#,##0.0x_)" Then
                            Selection.NumberFormat = "General"
                        Else
                            Selection.NumberFormat = "#,##0.0_);(#,##0.0)"
                        End If
                    End If
                End If
            End If
        ****Else
            Selection.NumberFormat = "#,##0.0_);(#,##0.0)"****
        End If
    End If
End Sub

First some background information.

From the documentation for the Excel.Range.NumberFormat Property :

Returns or sets a Variant value that represents the format code for the object.

Remarks

This property returns Null if all cells in the specified range don't have the same number format.

COM Variant Types can contain multiple sub-types and are marshaled to the .Net type System.Object .

From Marshaling Variant to Object

When marshaling a variant to an object, the type, and sometimes the value, of the marshaled variant determines the type of object produced. The following table identifies each variant type and the corresponding object type that the marshaler creates when a variant is passed from COM to the .NET Framework.

Partial Listing from above reference:

COM variant type   Object type
----------------   ---------------
VT_EMPTY           Null object reference (Nothing in Visual Basic).
VT_NULL            System.DBNull
VT_DISPATCH        System.__ComObject or null if (pdispVal == null)
VT_UNKNOWN         System.__ComObject or null if (punkVal == null)
VT_ERROR           System.UInt32
VT_BOOL            System.Boolean
VT_I1              System.SByte
VT_UI1             System.Byte
VT_I2              System.Int16
VT_UI2             System.UInt16

Since the Excel.Range.NumberFormat Property returns a Variant null (VT_Null) when the Range contains multiple formats, .Net will receive a System.DBNull object. Your posted code implies that you are aware of this, however the code is checking if the Excel.Range object is a DBNull and not the Excel.Range.NumberFormat Property.

So instead of:

If Not IsDBNull(Selection) Then

use:

If Not IsDBNull(Selection.NumberFormat) Then

Your code is also using implicit type casting that can lead to many debugging problems. I strongly recommend that you enable Option Strict as it will force you to think about the variable types you are using and your code will run quicker as well.

If you instead declared a variable like this:

Dim numberFormat As String = TryCast(Selection.NumberFormat, String)

then the conditional logic would be:

If numberFormat Is Nothing Then
    ' multiple formats exist in range
Else
    ' check numberFormat
End If

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM