Multiple Checkboxes = Text in Text Box - vba

I have a form I'm trying to build. I would like multiple checkboxs to ADD text to a textbox. I was unable to do to do that, without define alot! I used 3 Checkboxes in the original scenario. Now I have to do that using 12 checkboxes. I would like to know if there is an easier way to build this.
The fallowing shows what I used to with the original 3. I would really appreciate help so I don't have to do this for the next 12, it'd be A LOT! Thank you in advance!
Private Sub SUE_Click()
If SUE.value = True And SUD.value = False And SUG.value = False Then
StartUp.Value = "E DEGD"
Else
If SUD.value = True And SUE.value = False And SUG.value = False Then
StartUp.Value = "D DEGD"
Else
If SUG.value = True And SUD.value = False And SUE.value = False Then
StartUp.Value = "G DEGD"
Else
If SUD.value And SUE.value And SUG.value = True Then
StartUp.Value = "D DEGD, E DEGD, G ALT DEGD"
Else
If SUD.value And SUE.value = True Then
StartUp.Value = "D DEGD, E DEGD"
Else
If SUE.value And SUG.value = True Then
StartUp.Value = "E DEGD, G ALT DEGD"
Else
If SUD.value And SUG.value = True Then
StartUp.Value = "D DEGD, G ALT DEGD"
Else
If SUE.value = False Then
StartUp.Value = ""
Else
If SUD.value = False Then
StartUp.Value = ""
Else
If SUG.value = False Then
StartUp.Value = ""
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
End Sub

I really don't think this is the way to go. You're going to end up with lots of lines of code each time you need to add a checkbox.
With the following, the only thing you need to do is :
Create your userform with all the checkboxes you need (keep track of the captions).
In the main, create as many stringprovider objects as you need (probably as many as there are checkboxes), supply them with the string they need to produce and the caption of the checkbox to which they are linked.
Register the stringproviders with the stringbuilder.
supply the stringbuilder to the form.
What you need to do is:
Create a StringProvider class (you need to create a class module) as
follows
This is a very simple class that contains 3 pieces of information:
The string you want to produce
The Enabled/Disabled state
The caption (case sensitive) of the checkbox to which it is linked.
This object is designed to store the string value you want as an output, e.g. "E DEGD", as well as the name (in fact the Caption) of the checkbox (e.g. "SUE", "SUD" in your code) that is linked to it.
Option Explicit
Private Type TValueProvider
value As String
IsEnabled As Boolean
LinkledTB As String
End Type
Private this As TValueProvider
Public Property Get value() As String
value = this.value
End Property
Public Property Let value(v As String)
this.value = v
End Property
Public Property Get IsEnabled() As Boolean
IsEnabled = this.IsEnabled
End Property
Public Property Let IsEnabled(b As Boolean)
this.IsEnabled = b
End Property
Public Property Get LinkedTB() As String
LinkedTB = this.LinkledTB
End Property
Public Property Let LinkedTB(textboxname As String)
this.LinkledTB = textboxname
End Property
A stringbuilder class, with the following code:
This class will store all the stringprovider objects. When called, the UpdateString() sub will a) go through the registered stringproviders (in order of addition) and fire StringUpdated event that is used to inform the UserForm that the string was updated and that it needs to display it.
Option Explicit
Private Type TStringBuilder
stringproviders As Collection
End Type
Public Event StringUpdated(newstring As String)
Private this As TStringBuilder
Private Sub class_initialize()
Set this.stringproviders = New Collection
End Sub
Public Sub UpdateString()
Dim k As Variant
Dim sp As StringProvider
Dim arr() As String
Dim i As Long
Dim EnabledStringProviders As Collection
Set EnabledStringProviders = New Collection
For Each k In this.stringproviders
Set sp = k
If sp.IsEnabled Then
EnabledStringProviders.Add sp
End If
Next k
If EnabledStringProviders.Count = 0 Then
RaiseEvent StringUpdated(vbNullString)
Else
ReDim arr(EnabledStringProviders.Count - 1)
For Each k In EnabledStringProviders
Set sp = k
arr(i) = sp.value
i = i + 1
Next k
RaiseEvent StringUpdated(Join(arr, ", "))
End If
End Sub
Public Sub RegisterStringProvider(sp As StringProvider)
this.stringproviders.Add sp
End Sub
Public Function getSringProviderFromTBName(name As String)
Dim sp As StringProvider
Dim k As Variant
For Each k In this.stringproviders
Set sp = k
If sp.LinkedTB = name Then
Set getSringProviderFromTBName = sp
Exit Function
End If
Next k
Err.Raise vbObjectError + 1, , "Could not find stringprovider with name: " & name
End Function
This will hold a collection of stringproviders. When UpdateString() is called, it will go through the stringproviders and retrieve their value if they are updated.
You also need wrapper for the checkbox object, which would look, like this:
Option Explicit
Private WithEvents WrappedTB As MSForms.CheckBox
Private pstringbuilder As stringbuilder
Public Sub Initialize(ByVal tb As MSForms.CheckBox, sb As stringbuilder)
Set WrappedTB = tb
Set pstringbuilder = sb
End Sub
Private Sub wrappedTB_Change()
Dim sp As StringProvider
Set sp = pstringbuilder.getSringProviderFromTBName(WrappedTB.Caption)
sp.IsEnabled = WrappedTB.value
pstringbuilder.UpdateString
End Sub
The role of this wrapper is to capture the Checkbox_change event. Whenever a checkbox changes state, the wrappedTB_Change() sub is called. It requests the stringprovider linked to the checkbox from the stringbuilder and then calls the UpdateString method of the stringbuilder object. Note that stringbuilder holds references to the stringproviders so that an update to the stringprovider is automatically reflected inside the stringbuilder.
Your form should look like this:
Option Explicit
Private WithEvents pstringbuilder As stringbuilder
Private wrappers As Collection
Private Sub UserForm_initialize()
Set wrappers = New Collection
End Sub
Public Sub ShowDialog(sb As stringbuilder)
Dim wrapper As ChkBoxWrapper
Dim c As Control
Set pstringbuilder = sb
' This code discovers how many checkboxes you have in the userform, and creates one
' wrapper per checkbox. It supplies each wrapper with the same stringbuilder object
' the wrappers are then stored in the wrappers collection.
' That way you don't need to know how many checkboxes there are at compile time.
For Each c In Me.Controls
Set wrapper = New ChkBoxWrapper
If TypeName(c) = "CheckBox" Then
wrapper.Initialize c, sb
wrappers.Add wrapper
End If
Next c
Me.Show
End Sub
Private Sub pstringbuilder_StringUpdated(s As String)
' This handles the event from the stringbuilder object.
TextBox1.value = s
End Sub
As an example usage, this is module1:
Public Sub main()
Dim frm As UserForm1
Set frm = New UserForm1
Dim sp1 As StringProvider
Dim sp2 As StringProvider
Set sp1 = StringProviderFactory("Toto", "CheckBox1") ' This is where you associate the string you want to output with the checkbox Caption
Set sp2 = StringProviderFactory("Titi", "CheckBox2")
Dim sb As stringbuilder
Set sb = New stringbuilder
' Then you register each stringprovider with the stringbuilder.
sb.RegisterStringProvider sp1
sb.RegisterStringProvider sp2
frm.ShowDialog sb
End Sub
Private Function StringProviderFactory(value As String, linked_TB_name As String) As StringProvider
' Just a helper function to create stringproviders
Dim sp As StringProvider
Set sp = New StringProvider
sp.value = value
sp.LinkedTB = linked_TB_name
Set StringProviderFactory = sp
End Function
I hope this helps. The code can be very much improved on, but hopefully this will get you started.

Related

Check the item in ToolStripMenuItem dynamically through Sub Function

I am new to .Net Visual Basic, I am currently self learning and trying to make some small application.
I need a help on Checking a sub menu item of ToolStripMenuItem
Complete concept is like:
I have a datagridview in which user will be able to rearrange the column or make a column visible or Hidded for this I have Sub / Function like below:
Public Sub Fun_Grid_Colomn_Visibility(ByVal GridName As DataGridView, ByRef ColName As String, ByVal MS_col As ToolStripMenuItem, ChkVal As Boolean)
If ChkVal = True Then
With GridName
.Columns("" & ColName & "").Visible = False
End With
MS_col.Checked = False
Exit Sub
End If
If ChkVal = False Then
GridName.Columns("" & ColName & "").Visible = True
MS_col.Checked = True
Exit Sub
End If
End Sub
On the form close I will be saving the user grid format as below (Got code from another Q/A Post) :
Public Sub WriteGrideViewSetting(ByVal dgv As DataGridView, ByVal FileName As String)
Dim settingwriter As XmlTextWriter = New XmlTextWriter("C:\Users\<username>\Desktop\temp\" & FileName & ".xml", Nothing)
settingwriter.WriteStartDocument()
settingwriter.WriteStartElement(dgv.Name)
Dim count As Integer = dgv.Columns.Count
For i As Integer = 0 To count - 1
settingwriter.WriteStartElement("column")
settingwriter.WriteStartElement("Name")
settingwriter.WriteString(dgv.Columns(i).Name)
settingwriter.WriteEndElement()
settingwriter.WriteStartElement("width")
settingwriter.WriteString(dgv.Columns(i).Width.ToString())
settingwriter.WriteEndElement()
settingwriter.WriteStartElement("headertext")
settingwriter.WriteString(dgv.Columns(i).HeaderText)
settingwriter.WriteEndElement()
settingwriter.WriteStartElement("displayindex")
settingwriter.WriteString(dgv.Columns(i).DisplayIndex.ToString())
settingwriter.WriteEndElement()
settingwriter.WriteStartElement("visible")
settingwriter.WriteString(dgv.Columns(i).Visible.ToString())
settingwriter.WriteEndElement()
settingwriter.WriteEndElement()
Next
settingwriter.WriteEndElement()
settingwriter.WriteEndDocument()
settingwriter.Close()
End Sub
End Module
If the user is reopening the form I used the below (Q/A code) to rearrange Datagridview column as pervious :
Public Sub ReadDataGridViewSetting(ByVal dgv As DataGridView, ByVal FileName As String, ByRef Frm_name As Form)
Dim xmldoc As XmlDocument = New XmlDocument()
Dim xmlnode As XmlNodeList
Dim CMSN_ToolName As String
Dim Var_file_Chk As String = "C:\Users\<user>\Desktop\temp\" & FileName & ".xml"
If System.IO.File.Exists(Var_file_Chk) = True Then
Dim fs As FileStream = New FileStream(Var_file_Chk, FileMode.Open, FileAccess.Read)
xmldoc.Load(fs)
xmlnode = xmldoc.GetElementsByTagName("column")
For i As Integer = 0 To xmlnode.Count - 1
Dim columnName As String = xmlnode(i).ChildNodes.Item(0).InnerText.Trim()
Dim width As Integer = Integer.Parse(xmlnode(i).ChildNodes.Item(1).InnerText.Trim())
Dim headertext As String = xmlnode(i).ChildNodes.Item(2).InnerText.Trim()
Dim displayindex As Integer = Integer.Parse(xmlnode(i).ChildNodes.Item(3).InnerText.Trim())
Dim visible As Boolean = Convert.ToBoolean(xmlnode(i).ChildNodes.Item(4).InnerText.Trim())
dgv.Columns(columnName).Width = width
dgv.Columns(columnName).HeaderText = headertext
dgv.Columns(columnName).DisplayIndex = displayindex
dgv.Columns(columnName).Visible = visible
Next
fs.Close()
End If
End Sub
Now what I need is that a Function or Sub for the Itemmenu. If a Particular column is Visible in the datagridview then the particular Itemmenu should be checked else it would be unchecked. I need this function when Itemmenu is being displayed / opened.
what I tried just (for sample) in Itemmenu opening is like
Private Sub ColumnsToolStripMenuItem_DropDownOpening(sender As Object, e As EventArgs) Handles ColumnsToolStripMenuItem.DropDownOpening
If DGV_CompList.Columns("DGC_Est").Visible = True Then
Dim CMSN_ToolName = MS_CV_Est.Name
Dim unused As ToolStripMenuItem = New ToolStripMenuItem(CMSN_ToolName) With {
.Checked = True
}
End If
End Sub
DGV_CompList -> DataGridView
DGC_Est -> Column Name of datagridview
MS_CV_Est -> - ToolStripMenuItem which need to checked
(Note: I will be changing the MenuItem Name to Match Datagrid Column name for Sync)
But the ToolStripMenuItem is not getting checked.
Actually I need function / Sub where I will be able to pass the grid name and the Menuname and loop through the grid columns and check if the column is visible or not if the particular column is visible then I need to check that item in the itemmenu.
I am requesting for the sub / function because it can be used for any toolstripmenuitem in any form.
Thanks and Regards.
As per #Jimi's hint, assigned each required Menuitem's Tag property with the datagridview column name and created the below sub / function :
Public Sub Fun_ToolStripMenuItem_Check(ByVal dgv As DataGridView, ByVal TS_Menu_Items As ToolStripItemCollection)
For Each item As ToolStripMenuItem In TS_Menu_Items.OfType(Of ToolStripMenuItem)
If Not item.Tag = "" Then
If dgv.Columns(item.Tag).Visible = True Then
item.Checked = True
Else
item.Checked = False
End If
End If
For Each submenu_item As ToolStripMenuItem In item.DropDownItems.OfType(Of ToolStripMenuItem)
If Not submenu_item.Tag = "" Then
If dgv.Columns(submenu_item.Tag).Visible = True Then
submenu_item.Checked = True
Else
submenu_item.Checked = False
End If
End If
Next
Next
End Sub
Note in the loop used - " OfType(Of ToolStripMenuItem) " because I have ToolStripSeparator between the Itemmenus.
On mouse over called the Sub by :
Private Sub MS_ColumnVisible_DropDownOpening(sender As Object, e As EventArgs) Handles MS_ColumnVisible.DropDownOpening
Fun_ToolStripMenuItem_Check(DGV_CompList, MS_CompDGV.Items)
End Sub
'DGV_CompList' - Datagridview Name and 'MS_CompDGV' - ContextMenuStrip Name
More important is that I did not assign any value to the Tag property to Menuitems which are not used show or hide the datagridview columns.

Search dgv column by Column("TagIndex = 5")

I'm trying to get data from a DGV grid onto specific tags, and so far it has been working great. But an update moved the tags positions in the DGV so Rows(x) does not equal the tags I'm moving data into anymore.
Is it possible to do a search like the one I'm doing in Cells("Val") but in the Rows("") instead?
Actually I want it to be something like this Rows("TagIndex = 5") etc.
A full line of code would then be:
HopperStatus = dgvDataFlt.Rows("TagIndex = 5").Cells("Val").Value
but is this possible.
Row 12 & 13 are switched when logging
dgvDataFLT = dgvDataFloating
If dgvDataFlt.Rows(0).Cells("TagIndex").Value = 12 Then
'DGVDataFlt.AutoResizeColumns()
'--------------------------------------Floating TAGS fra database------------------------------------------
ProdRecCnt = dgvDataFlt.Rows(10).Cells("Val").Value
ProdTotCnt = dgvDataFlt.Rows(9).Cells("Val").Value
FrontFree = dgvDataFlt.Rows(8).Cells("Val").Value
CurrAutoMode = dgvDataFlt.Rows(7).Cells("Val").Value
PalletStatus = dgvDataFlt.Rows(6).Cells("Val").Value
HopperStatus = dgvDataFlt.Rows(5).Cells("Val").Value
PowerStatus = dgvDataFlt.Rows(4).Cells("Val").Value
CurrRecNo = dgvDataFlt.Rows(3).Cells("Val").Value
NomCycTime = dgvDataFlt.Rows(2).Cells("Val").Value
AutoStart = dgvDataFlt.Rows(1).Cells("Val").Value
MachineNo = dgvDataFlt.Rows(0).Cells("Val").Value
LOGTimeStamp = dgvDataFlt.Rows(0).Cells("DateAndTime").Value 'for aktuelle lognings tidstempel
LOGDateStamp = Microsoft.VisualBasic.Left(LOGTimeStamp, 10)
LOGClockStamp = Microsoft.VisualBasic.Mid(LOGTimeStamp, 12, 5)
End If
I want the code to look/work something like this:
If dgvDataFlt.Rows(0).Cells("TagIndex").Value = 12 Then
'DGVDataFlt.AutoResizeColumns()
'--------------------------------------Floating TAGS fra database------------------------------------------
ProdRecCnt = dgvDataFlt.Rows("TagIndex = 10").Cells("Val").Value
ProdTotCnt = dgvDataFlt.Rows("TagIndex = 9").Cells("Val").Value
FrontFree = dgvDataFlt.Rows("TagIndex = 8").Cells("Val").Value
CurrAutoMode = dgvDataFlt.Rows("TagIndex = 7").Cells("Val").Value
PalletStatus = dgvDataFlt.Rows("TagIndex = 6").Cells("Val").Value
HopperStatus = dgvDataFlt.Rows("TagIndex = 5").Cells("Val").Value
PowerStatus = dgvDataFlt.Rows("TagIndex = 4").Cells("Val").Value
CurrRecNo = dgvDataFlt.Rows("TagIndex = 3").Cells("Val").Value
NomCycTime = dgvDataFlt.Rows("TagIndex = 2").Cells("Val").Value
AutoStart = dgvDataFlt.Rows("TagIndex = 1").Cells("Val").Value
MachineNo = dgvDataFlt.Rows("TagIndex = 0").Cells("Val").Value
LOGTimeStamp = dgvDataFlt.Rows(0).Cells("DateAndTime").Value 'for aktuelle lognings tidstempel
LOGDateStamp = Microsoft.VisualBasic.Left(LOGTimeStamp, 10)
LOGClockStamp = Microsoft.VisualBasic.Mid(LOGTimeStamp, 12, 5)
End If
I would suggest adding a class and then inheriting the DataGridView control into that class. I have made a quick little example of this and the code works, but to get it to work you will have to perform a few steps:
(1) If you don't already have a windows forms application to test this then,
make a new one.
(2) Create class named KeyedDataGridView
(3) Copy and Paste the following Code into KeyedDataGridView class
(4) Rebuild your Project
(5) Drag and Drop new component onto your windows Form.
NOTE: This class is limited, but should still be able to do what you require of it.
Finally, if you need any help then, please leave a comment and will try to get to it when I can.
Option Explicit On
Public Class KeyedDataGridView
Inherits Windows.Forms.DataGridView
Dim _Rows As KeyedDataRows
Public Shadows Property Rows As KeyedDataRows
Get
Return _Rows
End Get
Set(value As KeyedDataRows)
_Rows = value
End Set
End Property
Public Sub New()
Dim strName As String
strName = Me.Name
strName = MyBase.Name
_Rows = New KeyedDataRows(Me)
_Rows.Rows = MyBase.Rows
End Sub
Protected Overrides Sub Finalize()
_Rows = Nothing
MyBase.Finalize()
End Sub
End Class
Public Class KeyedDataRows
Inherits Windows.Forms.DataGridViewRowCollection
Dim _TagNames As Dictionary(Of String, Integer)
Dim _Rows As DataGridViewRowCollection
Dim _Cells As Dictionary(Of String, DataGridViewCellCollection)
Dim dgv As DataGridView
Default Public Overloads ReadOnly Property Item(strTagName As String) As DataGridViewRow
Get
Return _Rows.Item(Me.IndexFromName(strTagName))
End Get
End Property
Protected Friend Property Rows As DataGridViewRowCollection
Get
Return _Rows
End Get
Set(value As DataGridViewRowCollection)
_Rows = value
End Set
End Property
Public Property TagName(index As Integer) As String
Get
Return CStr(_TagNames.Item(index))
End Get
Set(value As String)
_TagNames.Item(index) = value
End Set
End Property
Public Sub New(tmp As DataGridView)
MyBase.New(tmp)
dgv = tmp
_TagNames = New Dictionary(Of String, Integer)
_Cells = New Dictionary(Of String, DataGridViewCellCollection)
End Sub
Public Shadows Sub Add(strTagName As String)
Dim intCurRow As Integer
If dgv.AllowUserToAddRows Then
intCurRow = _Rows.Count - 1
Else
intCurRow = _Rows.Count
End If
_TagNames.Add(strTagName, intCurRow)
_Rows.Add()
End Sub
Public Shadows Sub Add(strTagName As String, dataGridViewRow As DataGridViewRow)
Dim intCurRow As Integer
If dgv.AllowUserToAddRows Then
intCurRow = _Rows.Count - 1
Else
intCurRow = _Rows.Count
End If
_TagNames.Add(strTagName, intCurRow)
_Rows.Add(dataGridViewRow)
End Sub
Public Shadows Sub Add(count As Integer, strTagNames() As String)
Dim intI As Integer
Dim intCurRow As Integer
If dgv.AllowUserToAddRows Then
intCurRow = _Rows.Count - 1
Else
intCurRow = _Rows.Count
End If
For intI = 0 To (count - 1)
_TagNames.Add(strTagNames(intI), intCurRow)
_Rows.Add()
intCurRow = _Rows.Count - 1
Next intI
End Sub
Public Property IndexFromName(strTagName As String) As Integer
Get
If _TagNames.Count > 0 Then
If _TagNames.ContainsKey(strTagName) Then
Return _TagNames.Item(strTagName)
Else
Return -1
End If
Else
Return -1
End If
End Get
Set(value As Integer)
_TagNames.Add(strTagName, value)
End Set
End Property
Public Overloads Sub RemoveAt(strTagName As String)
_Cells.Remove(strTagName)
_Rows.RemoveAt(IndexFromName(strTagName))
_TagNames.Remove(strTagName)
End Sub
Protected Overrides Sub Finalize()
_TagNames.Clear()
_TagNames = Nothing
_Cells.Clear()
_Rows.Clear()
_Cells = Nothing
_Rows = Nothing
MyBase.Finalize()
End Sub
End Class
I also, added the following buttons to a windows form to test the code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
With KeyedDataGridView1
.Rows.Add("Tag Test 1")
.Rows.Add("Tag Test 2")
.Rows.Add("Tag Test 3")
.Rows.Add("Tag Test 4")
End With
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
MsgBox(KeyedDataGridView1.Rows("Tag Test 3").Cells(0).Value & vbCrLf &
KeyedDataGridView1.Rows("Tag Test 3").Cells(1).Value & vbCrLf &
KeyedDataGridView1.Rows("Tag Test 3").Cells(2).Value)
MsgBox(KeyedDataGridView1.Rows("Tag Test 2").Cells(0).Value & vbCrLf &
KeyedDataGridView1.Rows("Tag Test 2").Cells(1).Value & vbCrLf &
KeyedDataGridView1.Rows("Tag Test 2").Cells(2).Value)
MsgBox(KeyedDataGridView1.Rows("Tag Test 1").Cells(0).Value & vbCrLf &
KeyedDataGridView1.Rows("Tag Test 1").Cells(1).Value & vbCrLf &
KeyedDataGridView1.Rows("Tag Test 1").Cells(2).Value)
End Sub

Adding List of Objects to Dropdown Combobox in Visual Basic

I am pretty new to Visual Basic and mostly create through trial and error but I've been attempting this for about 5 hours now and have had no luck. I am trying to create a program used at events for runners. It has multiple forms. There are two forms to create Runners and Races. These are then stored in the Runner and Race Collection Lists. I want to populate a dropdown box with the races that are stored in the race collection list. The closet I have got to achieving this so far is the dropdown displaying "{}collection". I have tried .datasource, .add and .addRange. None seem to work.
My race collection code is:
Public Class RaceList
Inherits System.Collections.CollectionBase
Public Sub Add(ByVal aRace As Race, Optional ByVal key As String = "NewRace")
List.Add(aRace)
End Sub
Public ReadOnly Property Item(ByVal index As Integer) As Race
Get
Return CType(List.Item(index), Race)
End Get
End Property
End Class
it should simply allow the user to add too and return races in the list.
Here is the code that allows the user to add a race to the list:
Public Class newRaceForm
Public Shared racelist As New RaceList
Private Sub uiBtnAddNewRace_Click(sender As System.Object, e As System.EventArgs) Handles uiBtnAddNewRace.Click
uiDTPRaceDate.Text = Today
Dim x As Date
Dim champ As Boolean = False
x = uiDTPRaceDate.Text
If uiCheckboxChampion.Checked = True Then
champ = True
End If
Dim race As New Race(x, champ)
uiCheckboxChampion.Checked = False
MsgBox("Race Added")
racelist.Add(race, race.uniqueRaceID)
End Sub
Finally, Here is the code on the form_load that should populate the box with the contents of racelist.
Private Sub finishRaceForm_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim x = 0
Dim races As New RaceList
While x < races.Count
uiDropDownRace.Items.Add(races.Item(x).ToString)
x = x + 1
End While
End Sub
Also, my races class is created as such:
Public Class Race
Private raceDate As String
Private isChampionship As Boolean
Public Shared RaceID As Integer = 0
Public uniqueRaceID As String
Sub New(ByVal x As String, champ As Boolean)
raceDate = x
If champ = True Then
isChampionship = True
Else
isChampionship = False
End If
RaceID = RaceID + 1
uniqueRaceID = "RaceID0" + RaceID.ToString
End Sub
End Class
Whenever you add an object to a list box or drop down list, the the ToString function is called, to determine what is going to be shown.
Most objects default to returning their type name as their ToString Function. You can overrride the ToString function to display whatever you wish. In the example below, I display the text "Race Number x" where x is the race number.
Public Class Race
Private raceDate As String
Private isChampionship As Boolean
Public Shared RaceID As Integer = 0
Public uniqueRaceID As String
Sub New(ByVal x As String, champ As Boolean)
raceDate = x
If champ = True Then
isChampionship = True
Else
isChampionship = False
End If
RaceID = RaceID + 1
uniqueRaceID = "RaceID0" + RaceID.ToString
End Sub
Public Overloads Function ToString() As String
Return "Race Number " & RaceID.ToString()
End Function
End Class
I'm working on a similar program and got it to work by using this.
Dim CmbAcro As String() = {"INSERT", "THE", "ITEMS", "YOU", "WANT", "TO", "ADD", "TO", "A", "COMBO", "BOX"}
Dim cmb As New DataGridViewComboBoxColumn()
cmb.HeaderText = "INSERT HEADER TEXT HERE"
cmb.Name = "INSERT NAME HERE"
cmb.MaxDropDownItems = 20
cmb.Sorted = True
For Each i In CmbAcro
cmb.Items.Add(i)
Next
DataGridView1.Columns.Add(cmb)

iterate custom dictionary object

Recently learned a bit of object oriented in Python, and I'm trying to do the same things in VBA.
I manage to construct a parent object (PC) that contains a dictionary of children objects:hooks. Hooks is also an object with a dictionary of children: rows.
All I want to do it to be able to write:
for each hook in PC
for each row in hook
sheets("X").cells(i,1) = contract.price
next row
next hook
Im looking at this but can't make it work...
Here summary of classes:
Class PC
Option Explicit
Public pPC As Object
Private pName As String
Private pInclude As Boolean
Private Sub Class_Initialize()
Set pPC = CreateObject("Scripting.Dictionary")
End Sub
Private Sub Class_Terminate()
Set pPC = Nothing
End Sub
Public Property Get hook(HookName As String) As CHook:
Set hook = pPC(HookName)
End Property
Public Sub Add(hook As CHook):
If Not pPC.exists(hook.Name) Then pPC.Add hook.Name, hook
End Sub
Public Property Get Include(HookName As String) As Boolean:
pInclude = pPC.exists(HookName)
Include = pInclude
End Property
Public Property Let Name(pcname As String):
pName = pcname
End Property
Public Property Get Name() As String:
Name = pName
End Property
Class Hook
Option Explicit
Public pHook As Object
Private pName As String
Private pLTFlatPrice As Double
Private pLTBasisPrice As Double
Private pLTDate As Date
Private Sub Class_Initialize()
Set pHook = CreateObject("Scripting.Dictionary")
pLTDate = Sheets("Control").Cells(2, 2)
End Sub
Private Sub Class_Terminate()
Set pHook = Nothing
End Sub
Public Sub AddRow(Row As CRow)
If Not pHook.exists(Row.ContractLot) Then pHook.Add Row.ContractLot, Row
If Row.TradeDate < pLTDate Then
pLTDate = Row.TradeDate
If IsNumeric(Row.FlatMV) And Row.FlatMV <> 0 Then pLTFlatPrice = Row.FlatMV
If IsNumeric(Row.BasisMV) Then pLTBasisPrice = Row.BasisMV
End If
End Sub
Public Property Get Row(ContractLot As String) As CRow:
Set Row = pHook.Item(ContractLot)
End Property
Public Property Let Name(HookName As String):
pName = HookName
End Property
Public Property Get Name() As String:
Name = pName
End Property
Public Property Get LTFlatPrice() As Double:
LTFlatPrice = pLTFlatPrice
End Property
Public Property Get LTBasisPrice() As Double:
LTBasisPrice = pLTBasisPrice
End Property
Public Property Get LTDate() As Double:
LTDate = pLTDate
End Property
and here is the peace of code where the error happens (Object doesn't support this property or method):
For i = 2 To UBound(path, 1)
tName = path(i, 1)
Next i
Set PC = SArray.PC(tName)
For Each hook In PC
For Each row In hook
With Sheets("COB")
.Cells(ii, 2) = row.PC
.Cells(ii, 3) = row.hook
.Cells(ii, 4) = row.Period
End With
ii = ii + 1
Next row
Next hook
You can iterate over either the keys or the items of a dictionary:
Sub Tester()
Dim d As New Scripting.Dictionary
Dim k
d.Add "one", 1
d.Add "two", 2
d.Add "three", 3
For Each k In d.Keys
Debug.Print k
Next
For Each k In d.Items
Debug.Print k
Next
End Sub
So, you can expose your dictionary as a property of an object and iterate over that. It does mean you need to specify .Items though (since it will default to keys.

ICSharpCode.TextEditor.TextEditorControl to VB.net UserControl Porting Problems

I am trying to create a vb.net usercontrol based on SharpDevelop TextEditor. I want syntax highlighting and code completion. In order to do that I decided to port CSharpCodeCompletion example from SharpDevelop's source code (version 3.2.1.6466). It is in folder "samples\CSharpCodeCompletion"
The control seems to run, syntax highlighting is OK and the code completion window is shown when the '.' (period) key is pressed. All the members are listed OK in completion window.
Right now I am facing three problems:
1. When the code completion window is shown any keystrokes are going to the editor and thus the search function in the listbox is not working.
2. When I select an entry from the listbox the word goes back to the editor but it deletes the period. For example I am typing "String." --> Listbox shows up --> Select the word "Empty" and I am getting "StringEmpty" in the editor.
3. In this command Return GetMemberText(ambience, CType(c, ICSharpCode.SharpDevelop.Dom.IMember)) I am getting a cast exception.
Please note that when I compile and run the original C# code from the example the editor and the completion window works as expected. My guess is focusing in two things, first there is a problem because I place the editor inside a usercontrol instead of a form as it is in the example, however I cannot see any obvious problem in my code pointing to this direction. Second there is a problem because of the porting of C# code to VB. C# isn't my thing at all but I tried my best (I know some Java) to rewrite the entire thing to VB.
I know that my code is big but I am posting the entire control code in case someone wants to load it to VS2010 and give it a try. In this case you are going to need ICSharpCode.NRefactory, ICSharpCode.SharpDevelop.Dom, ICSharpCode.TextEditor, log4net and Mono.Cecil assemblies from the example's bin folder.
Thank you and please forgive my English. Here is my Code
Public Class ctlVBCodeEditor
Private Class HostCallbackImplementation
Private Shared Sub ShowMessageWithException(msg As String, ex As Exception)
DevExpress.XtraEditors.XtraMessageBox.Show(msg & vbCrLf & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop)
End Sub
Private Shared Sub ShowMessage(msg As String)
DevExpress.XtraEditors.XtraMessageBox.Show(msg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop)
End Sub
Private Shared Sub ShowAssemblyLoadError(fileName As String, include As String, msg As String)
DevExpress.XtraEditors.XtraMessageBox.Show(msg & vbCrLf & "File: " & fileName & vbCrLf & "Include: " & include, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop)
End Sub
Public Shared Sub Register(ctlCode As ctlVBCodeEditor)
ICSharpCode.SharpDevelop.Dom.HostCallback.GetCurrentProjectContent = New Func(Of ICSharpCode.SharpDevelop.Dom.IProjectContent)(Function() ctlCode.myContent)
ICSharpCode.SharpDevelop.Dom.HostCallback.ShowError = New Action(Of String, System.Exception)(AddressOf ShowMessageWithException)
ICSharpCode.SharpDevelop.Dom.HostCallback.ShowMessage = New Action(Of String)(AddressOf ShowMessage)
ICSharpCode.SharpDevelop.Dom.HostCallback.ShowAssemblyLoadError = New Action(Of String, String, String)(AddressOf ShowAssemblyLoadError)
End Sub
End Class
Private Class CodeCompletionData
Inherits ICSharpCode.TextEditor.Gui.CompletionWindow.DefaultCompletionData
Implements ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionData
Private Shared vbAmbience As ICSharpCode.SharpDevelop.Dom.VBNet.VBNetAmbience = New ICSharpCode.SharpDevelop.Dom.VBNet.VBNetAmbience
Private Shared Function GetMemberImageIndex(m As ICSharpCode.SharpDevelop.Dom.IMember) As Integer
Dim Result As Integer = 0
If TypeOf m Is ICSharpCode.SharpDevelop.Dom.IMethod Then
Result = 1
ElseIf TypeOf m Is ICSharpCode.SharpDevelop.Dom.IProperty Then
Result = 2
ElseIf TypeOf m Is ICSharpCode.SharpDevelop.Dom.IField Then
Result = 3
ElseIf TypeOf m Is ICSharpCode.SharpDevelop.Dom.IEvent Then
Result = 6
Else
Result = 3
End If
Return Result
End Function
Private Shared Function GetClassImageIndex(cl As ICSharpCode.SharpDevelop.Dom.IClass) As Integer
Dim Result As Integer = 0
If cl.ClassType = ICSharpCode.SharpDevelop.Dom.ClassType.Enum Then
Result = 4
End If
Return Result
End Function
Private Shared Function GetEntityText(e As ICSharpCode.SharpDevelop.Dom.IEntity) As String
Dim Result As String = String.Empty
Dim amb As ICSharpCode.SharpDevelop.Dom.IAmbience = vbAmbience
If TypeOf e Is ICSharpCode.SharpDevelop.Dom.IMethod Then
Result = amb.Convert(CType(e, ICSharpCode.SharpDevelop.Dom.IMethod))
ElseIf TypeOf e Is ICSharpCode.SharpDevelop.Dom.IProperty Then
Result = amb.Convert(CType(e, ICSharpCode.SharpDevelop.Dom.IProperty))
ElseIf TypeOf e Is ICSharpCode.SharpDevelop.Dom.IEvent Then
Result = amb.Convert(CType(e, ICSharpCode.SharpDevelop.Dom.IEvent))
ElseIf TypeOf e Is ICSharpCode.SharpDevelop.Dom.IField Then
Result = amb.Convert(CType(e, ICSharpCode.SharpDevelop.Dom.IField))
ElseIf TypeOf e Is ICSharpCode.SharpDevelop.Dom.IClass Then
Result = amb.Convert(CType(e, ICSharpCode.SharpDevelop.Dom.IClass))
Else
Result = e.ToString
End If
Return Result
End Function
Public Shared Function XmlDocumentationToText(xmlDoc As String) As String
Dim sb As New System.Text.StringBuilder
Try
Using reader As New Xml.XmlTextReader(New IO.StringReader("<root>" & xmlDoc & "</root>"))
reader.XmlResolver = Nothing
While reader.Read
Select Case reader.NodeType
Case Xml.XmlNodeType.Text
sb.Append(reader.Value)
Case Xml.XmlNodeType.Element
Select Case reader.Name
Case "filterpriority"
reader.Skip()
Case "returns"
sb.AppendLine()
sb.Append("Returns: ")
Case "param"
sb.AppendLine()
sb.Append(reader.GetAttribute("name") + ": ")
Case "remarks"
sb.AppendLine()
sb.Append("Remarks: ")
Case "see"
If reader.IsEmptyElement Then
sb.Append(reader.GetAttribute("cref"))
Else
reader.MoveToContent()
If reader.HasValue Then
sb.Append(reader.Value)
Else
sb.Append(reader.GetAttribute("cref"))
End If
End If
End Select
End Select
End While
End Using
Return sb.ToString
Catch ex As Exception
Return xmlDoc
End Try
End Function
Private member As ICSharpCode.SharpDevelop.Dom.IMember
Private c As ICSharpCode.SharpDevelop.Dom.IClass
Private mOverloads As Integer = 0
Private _Description As String
Public Overrides ReadOnly Property Description As String
Get
If String.IsNullOrEmpty(_Description) Then
Dim entity As ICSharpCode.SharpDevelop.Dom.IEntity
If member IsNot Nothing Then
entity = CType(member, ICSharpCode.SharpDevelop.Dom.IEntity)
Else
entity = CType(c, ICSharpCode.SharpDevelop.Dom.IEntity)
End If
_Description = GetEntityText(entity)
If mOverloads > 1 Then _Description &= " (+" & mOverloads.ToString & " overloads"
_Description &= vbCrLf & XmlDocumentationToText(entity.Documentation)
End If
Return _Description
End Get
End Property
Public Sub AddOverload()
mOverloads += 1
End Sub
Public Sub New(theMember As ICSharpCode.SharpDevelop.Dom.IMember)
MyBase.New(theMember.Name, String.Empty, GetMemberImageIndex(theMember))
Me.member = theMember
End Sub
Public Sub New(theClass As ICSharpCode.SharpDevelop.Dom.IClass)
MyBase.New(theClass.Name, String.Empty, GetClassImageIndex(theClass))
Me.c = theClass
End Sub
End Class
Private Class CodeCompletionProvider
Implements ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider
Private ctlCode As ctlVBCodeEditor
Private Function FindExpression(txtArea As ICSharpCode.TextEditor.TextArea) As ICSharpCode.SharpDevelop.Dom.ExpressionResult
Dim finder As ICSharpCode.SharpDevelop.Dom.IExpressionFinder = New ICSharpCode.SharpDevelop.Dom.VBNet.VBExpressionFinder
Dim Result As ICSharpCode.SharpDevelop.Dom.ExpressionResult = finder.FindExpression(txtArea.Document.TextContent, txtArea.Caret.Offset)
If Result.Region.IsEmpty Then Result.Region = New ICSharpCode.SharpDevelop.Dom.DomRegion(txtArea.Caret.Line + 1, txtArea.Caret.Column + 1)
Return Result
End Function
Private Sub AddCompletionData(resultList As List(Of ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionData), completionData As ArrayList)
Dim nameDictionary As Dictionary(Of String, CodeCompletionData) = New Dictionary(Of String, CodeCompletionData)
'Add the completion data as returned by SharpDevelop.Dom to the
'list for the text editor
For Each obj As Object In completionData
If TypeOf obj Is String Then
'namespace names are returned as string
resultList.Add(New ICSharpCode.TextEditor.Gui.CompletionWindow.DefaultCompletionData(Convert.ToString(obj), "namespace " & obj.ToString, 5))
ElseIf TypeOf obj Is ICSharpCode.SharpDevelop.Dom.IClass Then
Dim cl As ICSharpCode.SharpDevelop.Dom.IClass = CType(obj, ICSharpCode.SharpDevelop.Dom.IClass)
resultList.Add(New CodeCompletionData(cl))
ElseIf TypeOf obj Is ICSharpCode.SharpDevelop.Dom.IMember Then
Dim mm As ICSharpCode.SharpDevelop.Dom.IMember = CType(obj, ICSharpCode.SharpDevelop.Dom.IMember)
If (TypeOf mm Is ICSharpCode.SharpDevelop.Dom.IMethod) AndAlso (CType(mm, ICSharpCode.SharpDevelop.Dom.IMethod).IsConstructor) Then
Continue For
End If
'Group results by name and add "(x Overloads)" to the
'description if there are multiple results with the same name.
Dim data As CodeCompletionData = Nothing
If nameDictionary.TryGetValue(mm.Name, data) Then
data.AddOverload()
Else
data = New CodeCompletionData(mm)
nameDictionary(mm.Name) = data
resultList.Add(data)
End If
Else
'Current ICSharpCode.SharpDevelop.Dom should never return anything else
Throw New NotSupportedException
End If
Next
End Sub
Public ReadOnly Property ImageList As System.Windows.Forms.ImageList Implements ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider.ImageList
Get
Return ctlCode.imageList1
End Get
End Property
Public ReadOnly Property PreSelection As String Implements ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider.PreSelection
Get
Return String.Empty
End Get
End Property
Public ReadOnly Property DefaultIndex As Integer Implements ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider.DefaultIndex
Get
Return -1
End Get
End Property
Public Function ProcessKey(key As Char) As ICSharpCode.TextEditor.Gui.CompletionWindow.CompletionDataProviderKeyResult Implements ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider.ProcessKey
If (Char.IsLetterOrDigit(key) Or key = " ") Then
Return ICSharpCode.TextEditor.Gui.CompletionWindow.CompletionDataProviderKeyResult.NormalKey
Else
Return ICSharpCode.TextEditor.Gui.CompletionWindow.CompletionDataProviderKeyResult.InsertionKey
End If
End Function
Public Function InsertAction(data As ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionData, textArea As ICSharpCode.TextEditor.TextArea, insertionOffset As Integer, key As Char) As Boolean Implements ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider.InsertAction
textArea.Caret.Position = textArea.Document.OffsetToPosition(insertionOffset)
Return data.InsertAction(textArea, key)
End Function
Public Function GenerateCompletionData(fileName As String, textArea As ICSharpCode.TextEditor.TextArea, charTyped As Char) As ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionData() Implements ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider.GenerateCompletionData
Dim resolver As New ICSharpCode.SharpDevelop.Dom.NRefactoryResolver.NRefactoryResolver(ctlCode.myContent.Language)
Dim rr As ICSharpCode.SharpDevelop.Dom.ResolveResult = resolver.Resolve(FindExpression(textArea), _
ctlCode.parseInfo, _
textArea.MotherTextEditorControl.Text)
Dim resultList As New List(Of ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionData)
If rr IsNot Nothing Then
Dim completionData As ArrayList = rr.GetCompletionData(ctlCode.myContent)
If completionData IsNot Nothing Then
AddCompletionData(resultList, completionData)
End If
End If
Return resultList.ToArray()
End Function
Public Sub New(myControl As ctlVBCodeEditor)
Me.ctlCode = myControl
End Sub
End Class
Private Class CodeCompletionKeyHandler
Private ctlCode As ctlVBCodeEditor
Private txtCode As ICSharpCode.TextEditor.TextEditorControl
Private codeCompletionWin As ICSharpCode.TextEditor.Gui.CompletionWindow.CodeCompletionWindow
Private Sub CloseCodeCompletionWindow(sender As Object, e As EventArgs)
If codeCompletionWin IsNot Nothing Then
RemoveHandler codeCompletionWin.FormClosed, AddressOf CloseCodeCompletionWindow
codeCompletionWin.Dispose()
codeCompletionWin = Nothing
End If
End Sub
Public Function TextAreaKeyEventHandler(key As Char) As Boolean
If codeCompletionWin IsNot Nothing Then
If codeCompletionWin.ProcessKeyEvent(key) Then
Return True
End If
End If
If key = "." Then
Dim completionDataProvider As ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider = New CodeCompletionProvider(Me.ctlCode)
Dim theForm As System.Windows.Forms.Form = Me.ctlCode.FindForm
codeCompletionWin = ICSharpCode.TextEditor.Gui.CompletionWindow.CodeCompletionWindow.ShowCompletionWindow(theForm, Me.txtCode, ctlVBCodeEditor.DummyFileName, completionDataProvider, key)
If codeCompletionWin IsNot Nothing Then
AddHandler codeCompletionWin.FormClosed, AddressOf CloseCodeCompletionWindow
End If
End If
Return False
End Function
Public Sub New(myControl As ctlVBCodeEditor, myCodeText As ICSharpCode.TextEditor.TextEditorControl)
Me.ctlCode = myControl
Me.txtCode = myCodeText
End Sub
Public Shared Function Attach(theControl As ctlVBCodeEditor, theEditor As ICSharpCode.TextEditor.TextEditorControl) As CodeCompletionKeyHandler
Dim Result As New CodeCompletionKeyHandler(theControl, theEditor)
AddHandler theEditor.ActiveTextAreaControl.TextArea.KeyEventHandler, AddressOf Result.TextAreaKeyEventHandler
AddHandler theEditor.Disposed, AddressOf Result.CloseCodeCompletionWindow
Return Result
End Function
End Class
Private Class ToolTipProvider
Private ctlCode As ctlVBCodeEditor
Private txtCode As ICSharpCode.TextEditor.TextEditorControl
Private Function GetText(result As ICSharpCode.SharpDevelop.Dom.ResolveResult) As String
If result Is Nothing Then
Return String.Empty
End If
If TypeOf result Is ICSharpCode.SharpDevelop.Dom.MixedResolveResult Then
Return GetText(CType(result, ICSharpCode.SharpDevelop.Dom.MixedResolveResult).PrimaryResult)
End If
Dim ambience As ICSharpCode.SharpDevelop.Dom.IAmbience = New ICSharpCode.SharpDevelop.Dom.VBNet.VBNetAmbience
ambience.ConversionFlags = ICSharpCode.SharpDevelop.Dom.ConversionFlags.StandardConversionFlags Or ICSharpCode.SharpDevelop.Dom.ConversionFlags.ShowAccessibility
If TypeOf result Is ICSharpCode.SharpDevelop.Dom.MemberResolveResult Then
Return GetMemberText(ambience, CType(result, ICSharpCode.SharpDevelop.Dom.MemberResolveResult).ResolvedMember)
ElseIf TypeOf result Is ICSharpCode.SharpDevelop.Dom.LocalResolveResult Then
Dim lrr As ICSharpCode.SharpDevelop.Dom.LocalResolveResult = CType(result, ICSharpCode.SharpDevelop.Dom.LocalResolveResult)
ambience.ConversionFlags = ICSharpCode.SharpDevelop.Dom.ConversionFlags.UseFullyQualifiedTypeNames Or ICSharpCode.SharpDevelop.Dom.ConversionFlags.ShowReturnType
Dim sb As New System.Text.StringBuilder
If lrr.IsParameter Then
sb.Append("parameter ")
Else
sb.Append("local variable ")
End If
sb.Append(ambience.Convert(lrr.Field))
Return sb.ToString
ElseIf TypeOf result Is ICSharpCode.SharpDevelop.Dom.NamespaceResolveResult Then
Return "namespace " & CType(result, ICSharpCode.SharpDevelop.Dom.NamespaceResolveResult).Name
ElseIf TypeOf result Is ICSharpCode.SharpDevelop.Dom.TypeResolveResult Then
Dim c As ICSharpCode.SharpDevelop.Dom.IClass = CType(result, ICSharpCode.SharpDevelop.Dom.TypeResolveResult).ResolvedClass
If c IsNot Nothing Then
'Return ambience.Convert(result.ResolvedType)
Return GetMemberText(ambience, CType(c, ICSharpCode.SharpDevelop.Dom.IMember))
Else
Return ambience.Convert(result.ResolvedType)
End If
ElseIf TypeOf result Is ICSharpCode.SharpDevelop.Dom.MethodGroupResolveResult Then
Dim mrr As ICSharpCode.SharpDevelop.Dom.MethodGroupResolveResult = CType(result, ICSharpCode.SharpDevelop.Dom.MethodGroupResolveResult)
Dim m As ICSharpCode.SharpDevelop.Dom.IMethod = mrr.GetMethodIfSingleOverload
If m IsNot Nothing Then
Return GetMemberText(ambience, m)
Else
Return "Overload of " & ambience.Convert(mrr.ContainingType) & "." & mrr.Name
End If
Else
Return String.Empty
End If
End Function
Private Shared Function GetMemberText(ambience As ICSharpCode.SharpDevelop.Dom.IAmbience, member As ICSharpCode.SharpDevelop.Dom.IMember) As String
Dim sb As New System.Text.StringBuilder
If TypeOf member Is ICSharpCode.SharpDevelop.Dom.IField Then
sb.Append(ambience.Convert(CType(member, ICSharpCode.SharpDevelop.Dom.IField)))
ElseIf TypeOf member Is ICSharpCode.SharpDevelop.Dom.IProperty Then
sb.Append(ambience.Convert(CType(member, ICSharpCode.SharpDevelop.Dom.IProperty)))
ElseIf TypeOf member Is ICSharpCode.SharpDevelop.Dom.IEvent Then
sb.Append(ambience.Convert(CType(member, ICSharpCode.SharpDevelop.Dom.IEvent)))
ElseIf TypeOf member Is ICSharpCode.SharpDevelop.Dom.IMethod Then
sb.Append(ambience.Convert(CType(member, ICSharpCode.SharpDevelop.Dom.IMethod)))
ElseIf TypeOf member Is ICSharpCode.SharpDevelop.Dom.IClass Then
sb.Append(ambience.Convert(CType(member, ICSharpCode.SharpDevelop.Dom.IClass)))
Else
sb.Append("unknown member ")
sb.Append(member.ToString())
End If
Dim documentation As String = member.Documentation
If (documentation IsNot Nothing) AndAlso (documentation.Length > 0) Then
sb.Append(vbCrLf)
sb.Append(CodeCompletionData.XmlDocumentationToText(documentation))
End If
Return sb.ToString
End Function
Private Sub OnToolTipRequest(sender As Object, e As ICSharpCode.TextEditor.ToolTipRequestEventArgs)
If e.InDocument And (Not e.ToolTipShown) Then
Dim expFinder As ICSharpCode.SharpDevelop.Dom.IExpressionFinder = New ICSharpCode.SharpDevelop.Dom.VBNet.VBExpressionFinder
Dim expResult As ICSharpCode.SharpDevelop.Dom.ExpressionResult = expFinder.FindFullExpression(txtCode.Text, txtCode.Document.PositionToOffset(e.LogicalPosition))
If expResult.Region.IsEmpty Then
expResult.Region = New ICSharpCode.SharpDevelop.Dom.DomRegion(e.LogicalPosition.Line + 1, e.LogicalPosition.Column + 1)
End If
Dim txtArea As ICSharpCode.TextEditor.TextArea = txtCode.ActiveTextAreaControl.TextArea
Dim resolver As New ICSharpCode.SharpDevelop.Dom.NRefactoryResolver.NRefactoryResolver(ctlCode.myContent.Language)
Dim rr As ICSharpCode.SharpDevelop.Dom.ResolveResult = resolver.Resolve(expResult, ctlCode.parseInfo, txtArea.MotherTextEditorControl.Text)
Dim toolTipText As String = GetText(rr)
If Not String.IsNullOrEmpty(toolTipText) Then
e.ShowToolTip(toolTipText)
End If
End If
End Sub
Public Sub New(myControl As ctlVBCodeEditor, myCodeText As ICSharpCode.TextEditor.TextEditorControl)
Me.ctlCode = myControl
Me.txtCode = myCodeText
End Sub
Public Shared Sub Attach(theControl As ctlVBCodeEditor, theEditor As ICSharpCode.TextEditor.TextEditorControl)
Dim tp As New ToolTipProvider(theControl, theEditor)
AddHandler theEditor.ActiveTextAreaControl.TextArea.ToolTipRequest, AddressOf tp.OnToolTipRequest
End Sub
End Class
Private Const DummyFileName As String = "dummy.vb"
Private pcREG As ICSharpCode.SharpDevelop.Dom.ProjectContentRegistry
Private myContent As ICSharpCode.SharpDevelop.Dom.DefaultProjectContent
Private parseInfo As ICSharpCode.SharpDevelop.Dom.ParseInformation
Private lastCompUnit As ICSharpCode.SharpDevelop.Dom.ICompilationUnit
Private parserThread As Threading.Thread
Private CurrentLanguageProperties As ICSharpCode.SharpDevelop.Dom.LanguageProperties
Private Sub InitializeControl()
parseInfo = New ICSharpCode.SharpDevelop.Dom.ParseInformation
CurrentLanguageProperties = ICSharpCode.SharpDevelop.Dom.LanguageProperties.VBNet
txtCode.SetHighlighting("VBNET")
HostCallbackImplementation.Register(Me)
CodeCompletionKeyHandler.Attach(Me, txtCode)
ToolTipProvider.Attach(Me, txtCode)
pcREG = New ICSharpCode.SharpDevelop.Dom.ProjectContentRegistry
'pcREG.ActivatePersistence(IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, "test"))
myContent = New ICSharpCode.SharpDevelop.Dom.DefaultProjectContent()
myContent.Language = CurrentLanguageProperties
End Sub
Private Function ConvertCompilationUnit(cu As ICSharpCode.NRefactory.Ast.CompilationUnit) As ICSharpCode.SharpDevelop.Dom.ICompilationUnit
Dim converter As New ICSharpCode.SharpDevelop.Dom.NRefactoryResolver.NRefactoryASTConvertVisitor(myContent)
cu.AcceptVisitor(converter, Nothing)
Return converter.Cu
End Function
Private Sub ParseStep()
Dim code As String = String.Empty
Invoke(New MethodInvoker(Sub() code = txtCode.Text))
Dim txtReader As IO.TextReader = New IO.StringReader(code)
Dim newCompUnit As ICSharpCode.SharpDevelop.Dom.ICompilationUnit
Dim supportedLanguage As ICSharpCode.NRefactory.SupportedLanguage = ICSharpCode.NRefactory.SupportedLanguage.VBNet
Using p As ICSharpCode.NRefactory.IParser = ICSharpCode.NRefactory.ParserFactory.CreateParser(supportedLanguage, txtReader)
'we only need to parse types and method definitions, no method bodies
p.ParseMethodBodies = False
p.Parse()
newCompUnit = ConvertCompilationUnit(p.CompilationUnit)
End Using
'Remove information from lastCompilationUnit and add from newCompilationUnit.
myContent.UpdateCompilationUnit(lastCompUnit, newCompUnit, DummyFileName)
lastCompUnit = newCompUnit
parseInfo.SetCompilationUnit(newCompUnit)
End Sub
Private Sub BackgroundParser()
BeginInvoke(New MethodInvoker(Sub() lblInfo.Text = "Loading Visual Basic..."))
myContent.AddReferencedContent(pcREG.Mscorlib)
'do one initial parser step to enable code-completion while other references are loading
ParseStep()
Dim refAssemblies As String() = {"System", _
"System.Data", _
"System.Drawing", _
"System.Xml", _
"System.Windows.Forms", _
"Microsoft.VisualBasic"}
For Each asmName As String In refAssemblies
Dim asmNameCopy As String = asmName
BeginInvoke(New MethodInvoker(Sub() lblInfo.Text = "Loading " & asmNameCopy & "..."))
Dim refContent As ICSharpCode.SharpDevelop.Dom.IProjectContent = pcREG.GetProjectContentForReference(asmName, asmName)
myContent.AddReferencedContent(refContent)
If TypeOf refContent Is ICSharpCode.SharpDevelop.Dom.ReflectionProjectContent Then
CType(refContent, ICSharpCode.SharpDevelop.Dom.ReflectionProjectContent).InitializeReferences()
End If
Next
myContent.DefaultImports = New ICSharpCode.SharpDevelop.Dom.DefaultUsing(myContent)
myContent.DefaultImports.Usings.Add("System")
myContent.DefaultImports.Usings.Add("System.Text")
myContent.DefaultImports.Usings.Add("Microsoft.VisualBasic")
BeginInvoke(New MethodInvoker(Sub() lblInfo.Text = "Ready..."))
'Parse the current file every 2 seconds
While Not IsDisposed
ParseStep()
Threading.Thread.Sleep(2000)
End While
End Sub
Protected Overrides Sub OnLoad(e As System.EventArgs)
MyBase.OnLoad(e)
If Not DesignMode Then
parserThread = New Threading.Thread(AddressOf BackgroundParser)
parserThread.IsBackground = True
parserThread.Start()
End If
End Sub
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
If Not DesignMode Then
InitializeControl()
End If
End Sub
End Class