vb.net Excel : Issue with getting Chart CategoryNames - excel

I need, for some reason, the category names of my chart. Here's what I got so far:
xlWorkbook = xlApp.ActiveWorkbook
Dim wsnat As Excel.Chart = TryCast(xlWorkbook.ActiveChart, Excel.Chart)
If Not wsnat Is Nothing Then
Dim axxxis As Excel.Axis = DirectCast(wsnat.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary), Excel.Axis)
Dim areyoukiddingme As Object = axxxis.CategoryNames
Dim arr As Array = DirectCast(areyoukiddingme, Array)
For q As Integer = 0 To arr.GetUpperBound(0)
Debug.Print(arr(q).ToString) ' HERE, the array 'arr' has two things which are EMPTY!
Next
End If
My problem is, that the array (arry) has the correct amount of EMPTY objects. If I do the whole thing in VBA, it works as expected. But it does not for VB.net. Any clues?
Here's the code in VBA:
Sub test()
Dim chrt As Chart
Set chrt = ActiveChart
Dim names As Variant
names = chrt.Axes(xlCategory, xlPrimary).CategoryNames
End Sub
This sub nicely outputs the category names of my chart!

Related

VBA code working when I step through it, but not when it's run

I have some basic VBA that is allowing a user to take a field from one table and use it to update another table. It works fine when I step through it, but nothing happens when I run it using F5. I don't get any errors, just nothing happens.
I think it could possibly be that the value hasn't been assigned to one of the variables before the next step occurs, but I've never had that problem before, and I've always assumed VBA wouldn't move to the next step until it had completed the one it's on?
My code is below:
Option Explicit
Sub acceptDateComp()
'set data type
Dim dtType As String
dtType = "opportunity"
'declare sheets
Dim wsComp As Worksheet
Set wsComp = ThisWorkbook.Sheets(dtType & "Comp")
Dim wsBCE As Worksheet
Set wsBCE = ThisWorkbook.Sheets(dtType & "Snapshot")
Dim wsOffline As Worksheet
Set wsOffline = ThisWorkbook.Sheets(dtType & "Database")
'declare tables
Dim bce As ListObject
Set bce = wsBCE.ListObjects(dtType & "Snapshot")
Dim offline As ListObject
Set offline = wsOffline.ListObjects(dtType & "Database")
Dim dateComp As ListObject
Set dateComp = wsComp.ListObjects(dtType & "DateComp")
'declare heights and areas
Dim offlineRange As Range
Set offlineRange = offline.ListColumns(1).DataBodyRange
'check for acceptance, then change values
Dim i As Long
Dim dateID As Long
Dim offlineRow As Long
Dim bceDate As String
For i = 2 To dateComp.ListRows.Count + 1
If dateComp.ListColumns(6).Range(i).Value = "Yes" Then
dateID = dateComp.ListColumns(1).Range(i).Value
offlineRow = Application.WorksheetFunction.Match(dateID, offlineRange, 0)
bceDate = dateComp.ListRows(i - 1).Range(5).Value
offline.ListRows(offlineRow).Range(12).Value = bceDate
End If
Next i
Call opportunityComp
End Sub

VBA : Getting an error for my code "Runtime error 424"

My code is working fine but it ends up giving me a runtime error "object required.
I am not able to find out what is causing this error. This code is related to deleting graphs that don't have any data in them .
Sub HideEmptyCharts()
Dim wksCharts As Worksheet
Dim objCO As ChartObject
' Set up a variable for the worksheet containing the charts
Set wksCharts = ThisWorkbook.Sheets("Report output")
' Loop through every embedded chart object on the worksheet
For Each objCO In wksCharts.ChartObjects
' Make each one visible
objCO.Visible = True
' If the chart is empty make it not visible
If IsChartEmpty(objCO.Chart) Then objCO.Visible = False
Next objCO
End Sub
Private Function IsChartEmpty(chtAnalyse As Chart) As Boolean
Dim i As Integer
Dim j As Integer
Dim objSeries As Series
' Loop through all series of data within the chart
For i = 1 To chtAnalyse.SeriesCollection.Count
Set objSeries = chtAnalyse.SeriesCollection(i)
' Loop through each value of the series
For j = 1 To UBound(objSeries.Values)
' If we have a non-zero value then the chart is not deemed to be empty
If objSeries.Values(j) <> 0 Then
' Set return value and quit function
IsChartEmpty = False
Exit Function
End If
Next j
Next i
IsChartEmpty = True
End Function
Change the object passed to the function from Chart to full ChartObjectlike this:
Private Sub HideEmptyCharts()
Dim wksCharts As Worksheet
Dim objCO As ChartObject
Set wksCharts= ThisWorkbook.Sheets("Report output")
For Each objCO In wksCharts.ChartObjects
objCO.Visible = True
If IsChartEmpty(objCO) Then objCO.Visible = False
Next objCO
End Sub
Private Function IsChartEmpty(co As ChartObject) As Boolean
Dim i As Integer
Dim j As Integer
Dim objSeries As Series
For i = 1 To co.Chart.SeriesCollection.Count
Set objSeries = co.Chart.SeriesCollection(i)
For j = 1 To UBound(objSeries.Values)
If objSeries.Values(j) <> 0 Then
IsChartEmpty = False
Exit Function
End If
Next j
Next i
IsChartEmpty = True
End Function
An outdated pivotcache and some still remembered but in the meantime missed items caused some trouble to me in the past. So I propose to add this code once before:
Dim pc As PivotCache
For Each pc In ThisWorkbook.PivotCaches
pc.MissingItemsLimit = xlMissingItemsNone
pc.Refresh
Next pc

Visual Basic - Closing excel still leaves processes

I have created some code to populate combo boxes on my form from a excel file when the form loads.
As part of the code, it is supposed to release the objects associated but it does not
Dim excel As New Excel.Application
Dim w As Excel.Workbook = excel.Workbooks.Open("C:\Email Template\Violations Log\Violations Log.xlsx")
Dim sheet As Excel.Worksheet = w.Worksheets("Individual Data")
Dim r As Excel.Range = sheet.Range("A2:A300")
Dim array(,) As Object = r.Value(excel.XlRangeValueDataType.xlRangeValueDefault)
Dim sheet2 As Excel.Worksheet = w.Worksheets("Category")
Dim s As Excel.Range = sheet2.Range("A2:A20")
Dim array2(,) As Object = s.Value(excel.XlRangeValueDataType.xlRangeValueDefault)
Dim bound0 As Integer = array.GetUpperBound(0)
Dim bound1 As Integer = array.GetUpperBound(1)
Dim j As Integer
Dim x As Integer
Dim s1 As String
If array IsNot Nothing Then
' Loop over all elements.
For j = 1 To bound0
For x = 1 To bound1
s1 = array(j, x)
If s1 IsNot Nothing Then
If Not ComboBox1.Items.Contains(s1.ToString) Then
ComboBox1.Items.Add(s1.ToString)
End If
End If
Next
Next
End If
If array IsNot Nothing Then
' Loop over all elements.
For j = 1 To bound0
For x = 1 To bound1
s1 = array2(j, x)
If s1 IsNot Nothing Then
If Not ComboBox2.Items.Contains(s1.ToString) Then
ComboBox2.Items.Add(s1.ToString)
End If
End If
Next
Next
End If
w.Close(False)
excel.Quit()
ReleaseObject(excel.XlRangeValueDataType.xlRangeValueDefault)
ReleaseObject(excel)
ReleaseObject(array)
ReleaseObject(array2)
ReleaseObject(r)
ReleaseObject(s)
ReleaseObject(sheet)
ReleaseObject(sheet2)
ReleaseObject(w)
ReleaseObject(bound0)
ReleaseObject(bound1)
ReleaseObject(j)
ReleaseObject(x)
ReleaseObject(s1)
Ive tried to release every object that is referenced but it still has a connection to the excel document.
Have I missed an object? or something bigger?
I have another code that copies from the form to that same excel document and that does not leave any processes open. (I have to kill the excel process that is created from loading the form to be able to use the code to copy data)
Any help would be greatly appreciated.
Figured it out.
The code would stop running and not complete the release object section of the code.
Using debugging I found that I was getting an error message which was muted. I resolved the error message and now it runs fine.
Thanks for trying to help.

Count lines (max) with values

I would like to count the lines that have values. I tried oSheet.Rows.Count but that doesn't work. Any idea about this?
My code is the following:
Dim oExcel As Object
Dim oBook As Object
Dim oSheet As Object
oExcel = CreateObject("Excel.Application")
oBook = oExcel.Workbooks.Add
oSheet = oBook.Worksheets("Sheet")
oSheet.Range("A" & max).Value = "0000111"
oSheet.Range("B1").Value ="Name"
oBook.SaveAs("C:\New folder\excel\" & datenw & ".xlsx")
oExcel.Quit()
As said in the comments, the following code should get you the count of rows that have values based on your Range:
Dim rowCount As Integer = oSheet.UsedRange.Rows.Count()
There is however a slight issue with your code I believe. This probably won't work:
oSheet = oBook.Worksheets("Sheet")
The reason it won't, is because "Sheet" doesn't exist on a new Workbook. "Sheet1" does, so this needs to be changed to:
oSheet = oBook.Worksheets("Sheet1")
'or
oSheet = oBook.Worksheets(1) 'remember Excel collections are one based not zero based
Lastly I would look at the way you are closing Excel as oExcel.Quit() is probably leaving an instance of Excel running. Have a look at this answer which links to Siddharth Rout's bit of code:
Private Sub ReleaseObject(ByVal obj As Object)
Try
Dim intRel As Integer = 0
Do
intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
Loop While intRel > 0
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
You also to make sure you release in the right order and release everything. This is usually in backwards order:
ReleaseObject(oSheet)
oBook.Close()
ReleaseObject(oBook)
oExcel.Quit()
ReleaseObject(oExcel)
However with all that said I would look at using the Microsoft.Office.Interop.Excel namespace directly rather than declaring objects:
Imports Microsoft.Office.Interop
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim oExcel As New Excel.Application
Dim oWorkbooks As Excel.Workbooks = oExcel.Workbooks
Dim oWorkbook As Excel.Workbook = oWorkbooks.Add()
Dim oSheets As Excel.Sheets = CType(oWorkbook.Sheets, Excel.Sheets)
Dim oWorksheet As Excel.Worksheet = CType(oSheets(1), Excel.Worksheet)
Dim oARange As Excel.Range = oWorksheet.Range("A" & max.ToString()) 'Not sure what max is but I took the assumption it's an Integer
oARange.Value = "0000111"
Dim oBRange As Excel.Range = oWorksheet.Range("B1")
oBRange.Value = "Name"
Dim oUsedRange As Excel.Range = oWorksheet.UsedRange()
Dim rowCount As Integer = oUsedRange.Rows.Count()
oWorkbook.SaveAs("C:\Test.xlsx")
ReleaseObject(oUsedRange)
ReleaseObject(oBRange)
ReleaseObject(oARange)
ReleaseObject(oWorksheet)
ReleaseObject(oSheets)
oWorkbook.Close()
ReleaseObject(oWorkbook)
ReleaseObject(oWorkbooks)
oExcel.Quit()
ReleaseObject(oExcel)
End Sub
Private Sub ReleaseObject(ByVal obj As Object)
Try
Dim intRel As Integer = 0
Do
intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
Loop While intRel > 0
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
End Class
I would also then look at turning Option Strict On:
Restricts implicit data type conversions to only widening conversions, disallows late binding, and disallows implicit typing that results in an Object type.
Define a row variable as Long, then start a loop which will end when it finds a blank value in column A:
Dim lRow as Long = 1
Do until oSheet.Range("A" & lRow).Value=""
' increment the loop variable
lRow+=1
Loop
' display the result in a message block
MsgBox(lRow-1)

Get Excel Chart datasource

It is easy to set a datasource for an Excel Chart with Visual Studio, like
Chart.SetSourceData(Source:=SomeRange)
But how do I GET (retrieve) the datasource (Range) for an already exisiting Chart in an Excel file ?
Here's a function that will parse the ranges out of the series. If you have custom series formulas that don't use ranges, it will probably break.
Public Function GetSourceData(ByRef cht As Chart) As Range
Dim srs As Series
Dim vaArgs As Variant
Dim i As Long
Dim rReturn As Range
For Each srs In cht.SeriesCollection
vaArgs = Split(Split(srs.Formula, "SERIES(")(1), ",")
For i = 0 To UBound(vaArgs) - 1
If rReturn Is Nothing Then
Set rReturn = Range(vaArgs(i))
Else
Set rReturn = Union(rReturn, Range(vaArgs(i)))
End If
Next i
Next srs
Set GetSourceData = rReturn
End Function
Use as:
?getsourcedata(activechart).Address
$B$2:$C$2,$A$3:$C$14
I think its been solved here already:
Excel VBA - Get chart data range
https://stackoverflow.com/a/28391220/6868389
The Visual Studio code looks like this:
Dim g As String
Dim gg() As String
Dim a As Excel.ChartObject
a = Globals.ThisAddIn.Application.ActiveSheet.chartobjects(1)
g = a.Chart.SeriesCollection(1).formula
gg = g.Split(",")
MsgBox(gg(2))

Resources