When I try to use .SetFormulas to reference Connector shapes on different page, I keep getting the #Name? error. The error would occur in both Visio 2010 and 2016. The code below works for circles and grouped shapes but not my connectors.
Dim formArray as String() = BuildFormulaArray(PreviousPageShapeIDs)
Dim theStream as Short() = StreamBuilder(CurrentShapeIDs, CustPropSection, Row, Cell)
Dim objArray as Object() = formArray.ConverToObject 'convenience function to convert each item to an object
vPage.SetFormulas(theStream, objArray, VisGetSetArgs.visSetBlasGuards)
However, the code below works with the connectors
For i = 0 to formArray.GetUpperBounds(0)
Dim streamInd as Integer = 4*i
vPage.Shapes(theStream(streamInd)).CellsSRC(theStream(streamInd+1),theStream(streamInd+2),theStream(streamInd+3)).FormulaForce = formArray(i)
Next
My formula is referencing cells using the Pages[PageName]!Sheet.ShapeID!CellName method.
I know I can make this work by using CellsSRC or using the shape name in my formula, but I would rather stick with using SetFormulas and shape IDs for speed reasons. Any ideas on why Visio is behaving inconsistently?
Related
I have created this script to generate a container that I want to use it to generate containers It works fine but I also need to be able to give the containers a custom header. As you can see I tried to capture the shape id in a variable so I could use the variable to get the shape Id for the container. Nevertheless, I cannot get the shape id or assign one statically I also found out that the container has more than one shape ID. How do I Identify the ID for the header portion. I also need to be able to drop shapes in the container. I followed Microsoft instructions and tried using
vsoContainerShape.ContainerProperties.AddMember vsoShape,
visMemberAddExpandContainer
However that doesn’t work.
Sub Add_Container()
Dim DiagramServices As Integer
DiagramServices = ActiveDocument.DiagramServicesEnabled
ActiveDocument.DiagramServicesEnabled = visServiceVersion140 +
visServiceVersion150
Dim visapp As Visio.Application
Dim vlan30 As Visio.Document
Dim node As Visio.Shape
Dim vlan30id As Integer
Application.Documents.OpenEx(Application.GetBuiltInStencilFile(visBuiltInStencilContainers, visMSUS), visOpenHidden)
Application.Windows.ItemEx("container.vsdm").Activate 'need to activate
Application.ActiveWindow.Page.DropContainer vlan30.Masters.ItemU("Classic"), Nothing
vlan30id = vlan30.ID
Debug.Print vlan30id
Dim v30chars As Visio.Characters
Set v30chars = Application.ActiveWindow.Page.Shapes.ItemFromID(vlan30id).Characters
v30chars.Begin = 0
v30chars.End = 7
v30chars.Text = "Vlan_30"
vlan30.Close
ActiveWindow.DeselectAll
'Restore diagram services
ActiveDocument.DiagramServicesEnabled = DiagramServices
End Sub
I need to be able to get the shape id for the heading of the containers and stored in a variable so I can use the variable for passing the argument in the ItemFromID. Thanks
First things first: your exact question was already answered her: http://visguy.com/vgforum/index.php?topic=6787.0
I packaged the whole code into a function, calling the function will drop a classic container on the page you passed as argument and fill the caption with the passed caption argument. The return value is the dropped Container, bottom function shows how to use the function and add shapes to the container.
'#Folder("ExampleDropContainer")
Option Explicit
Public Function DropContainerWithCaption(pg As Visio.Page, caption As String) As Visio.Shape
Dim vsPg As Visio.Page
Set vsPg = pg
Dim vsStencilName As String
vsStencilName = Application.GetBuiltInStencilFile(visBuiltInStencilContainers, visMSUS)
Dim vsStencil As Visio.Document
Set vsStencil = Application.Documents.OpenEx(vsStencilName, visOpenHidden)
Dim vsMas As Visio.Master
Set vsMas = vsStencil.Masters.ItemU("Classic")
'If you already had the shapes you want to have inside the continer you can replace "Nothing" with them.
Dim droppedContainer As Visio.Shape
'Set droppedContainer = vsPg.DropContainer(vsMas, Nothing)
'Using page.Drop circumvents some issues when a shape already occupies the space where the shape is to be dropped.
Set droppedContainer = vsPg.Drop(vsMas, 0, 0)
droppedContainer.Text = caption
Set DropContainerWithCaption = droppedContainer
End Function
Sub TestExample()
Dim newContainer As Visio.Shape
Set newContainer = DropContainerWithCaption(ActivePage, "Bananas")
'Example on how to add a Shape to the container, someShape is a visio.shape object
'newContainer.ContainerProperties.AddMember someShape
End Sub
You seem to have posted a lot of questions concerning the same or similar problems lately, most of which are quite basic once you get to know VBA. You should read up a bit, especially on the concept of return values of functions. Also be aware that most questions regarding programming in Visio are exactly the same in VBA for Excel, only the interaction with the document/workbook is sometime different. Many answers can be found when searching properly
Some good links are:
How to avoid Select Probably the most read article concerning VBA in Stackoverflow
ExcelMacroMastery Good Resource, a lot on the basics of programming in VBA
Chip Pearson's Website Lots of great and deep information
RubberduckVBA Blog Fantastic resource with many examples on how to bring VBA-Code up to modern standards. He's also active here on SO
The first two links are a must-read IMHO, the other two are great if you want to dive deeper into VBA.
A part of this question concerns doing the reverse of the following one:
VB.net get location of userControl in another container
No matter what I do, I cannot seem to pinpoint the location of my chart inside a userform (D inside A), therefore what I save is something very different than the chart alone.
So, provided that my userform is too like this:
I need to save a screenshot of D, being D a polar chart with a title and a legend.
My code is:
Dim PicFile As String = FilesFolder & "Pic.png"
Dim myBounds As Rectangle = A.D.Bounds
Dim BitMap As New Bitmap(myBounds.Width, myBounds.Height)
Dim PtChart As Point
PtChart = A.PointToScreen(New Point(0, 0))
PtChart = A.D.PointToClient(PtChart)
Using g As Graphics = Graphics.FromImage(BitMap)
g.CopyFromScreen(PtChart, Point.Empty, myBounds.Size)
End Using
BitMap.Save(PicFile, System.Drawing.Imaging.ImageFormat.Png)
Why does this not save the chart (D) correctly?
BONUS: how can I make it work even when I have another application open (say, internet browser) on top of the userform?
Don't have much experience with forms/listboxes. The following function aims to remove an array element by passing it to ListBox and using ListBox.RemoveItem method. What i am struggling with is creating/deleting ListBox object programmatically. I do know there are ActiveX and Form ListBox types but recording a code by adding both manually looks identical:
ActiveSheet.ListBoxes.Add(273, 289.5, 72, 71.25).Select
Here is the attempted function:
Function ArraylessElement(arrIn As Variant, ElemNo As Integer) As Variant
''''''''''''''''''''''''''''''''
'removes i element from 1D array by assigning to ListBox
'returns 1D array w/ Transpose
''''''''''''''''''
Dim lBox As ListBox
With ActiveSheet
Set lBox = .ListBoxes.Add(261, 279.75, 72, 71.25)
lBox.List = arrIn
lBox.RemoveItem (ElemNo - LBound(arrIn) - 1) '(LBound) of a ComboBox/ ListBox is 0.
ArraylessElement = Application.Transpose(lBox.List)
lBox.Delete
End With
End Function
I'm getting
Unable to set the list property of the ListBox class
error on lBox.List = arrIn line.
PS. I did see a DeleteArrayElement function at http://www.cpearson.com/excel/vbaarrays.htm which i will use if i cannot get mine working.
I am using the below code in Blue prism for filtering in excel for multi criteria.
But i am not able to filter multi criteria for Not equal to scenario.
Dim wb As Object
Dim excel as Object
Dim range as Object
Try
wb = GetWorkbook(Handle, Workbook)
excel = wb.Application
range = excel.Range(FRange)
Dim listOfValues as Array
listOfValues = Split(FCriteria,";")
wb.worksheets(Worksheet).select
range.select
range.Autofilter(FCol,listOfValues,7)
Success = True
Catch e As Exception
Success = False
Message = e.Message
Finally
wb = Nothing
End Try
Please help me tweaking the script
I'm almost sure that there is no filter option to set a "negative list". You can specify either a (positive) list of values (this is what your code does so far, for this you have to set the 7 as third parameter), or you can give a maximum of 2 individual criteria (in Excel, choose "Custom Filter" to set them.
You should play with the filter directly in Excel and try to set it like you want. Once you are satisfied with it, clear the filter, record a macro and repeat the filtering. Go to the VBA editor and see what's in there. It is straightforward to translate this into C# code.
But:
It's not possible to set any filtering by code (neither C# nor VBA) that you cannot set via the Excel GUI
I would question what you are trying to do. Since you are using Blue Prism, you should be trying to access the underlying data in a BP Collection(VB DataTable), rather than applying a filter, which is a visual tool for humans to further play with the interface. The robot will still have to do something with the filtered data, and it far easier to write code to proceed with data during the loop.
Otherwise use the Filter Collection Page of the 'Utilities - Collection Manipulation' VBO to get a filtered collection.
Also you are using VBA Split function, when you should use Split in VB as a method of the String.
Try this for a new page in the 'Utilities - Collection Manipulation' VBO(untested):
Dim NewRow As DataRow
Collection_Out = Collection_In.Clone
Dim Select_Concat As String
Select_Concat = "NOT(" & fieldName & " = '" & [String].Join("' OR " & fieldName & " = '", FCriteria.Split(";"c)) & "')"
For Each parentRow As DataRow In Collection_In.Select(Select_Concat)
NewRow = Collection_Out.NewRow
For Each c As DataColumn In NewRow.Table.Columns
NewRow(c.ColumnName) = parentRow(c.ColumnName)
Next c
Collection_Out.Rows.Add(NewRow)
Next parentRow
NewRow = Nothing
Collection_In = Nothing
Inputs: Collection_In(Collection), fieldName(Text), FCriteria(Text)
Outputs: Collection_Out(Collection)
You first need to get the entire range into an unfiltered Collection(which will be your Collection_In to this page, and then get the filtered Collection out....
This may sound dumb but can someone explain the reason why I need to include this extra code in vb.net that I don't need in VBA when changing the color of a cell.
I wrote a program that creates and saves an excel file using the microsoft.office.interop reference. Here is my code:
Public Class Export_Excel_Class
Public excelapp As Microsoft.Office.Interop.Excel.Application
Public excelbook As Microsoft.Office.Interop.Excel.Workbook
Public excelsheet As Microsoft.Office.Interop.Excel.Worksheet
Public Sub newExcel()
excelapp = New Microsoft.Office.Interop.Excel.Application
excelbook = excelapp.Workbooks.Add()
excelsheet = excelbook.Sheets("sheet1")
excelsheet.Range("A1").Select()
excelsheet.Range("a1").AddComment("hello")
excelsheet.Range("a1:B10").Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Yellow)
excelbook.SaveAs("C:\Users\DatOneBull\Desktop\Excel_Test")
excelapp.Quit()
End Sub
On the line that sets the color I had originally had tried excelsheet.Range("a1:B10").Interior.Color =
and tried to set a color but the color proptery is read only. I found the solution online but there was no explanation. Can someone tell me what this section of code means and why it is able to set the color value of th range?
System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Yellow)
VB.NET stores colors differently to VBA. The ToOle function converts the VB.NET color to the equivalent VBA version. This is an example of marshalling.
(If you are interested, the "OLE" in "ToOle" stands for "Object Linking and Embedding" which is an older way for windows programs to communicate with each other)
In VBA, you would set the color something like this:
Range("A1").Interior.Color = Excel.XlRgbColor.rgbYellow
' Or
Range("A2").Interior.Color = VBA.RGB(255, 255, 0)
Note that I purposely fully qualified the VBA code. This is valid VBA code, but in a style you rarely see.
In VB.Net you can do it like:
ws.Range("A1").Interior.Color = Excel.XlRgbColor.rgbYellow
ws.Range("A2").Interior.Color = Microsoft.VisualBasic.Information.RGB(255, 255, 0)
essentially the same code. Or you can do it like you are currently doing.
The net effect is the same; an integer value that represents color is being assigned to the Interior.Color property. Either you use a function to compute that value, or you use a constant. The various .Net functions are equivalents to the VBA.RGB function. VBA knows nothing about colors defined as a System.Drawing.Color, hence a conversion function is necessary.