Sorting the TimeZoneCollection list - sorting

Issue definition
I use the OpenNetCF TimeZoneCollection class to display in a ComboBox all the available time zones.
Dim tzc As New TimeZoneCollection
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
For Each tzi As TimeZoneInformation In tzc
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
But they are not sorted:
How could I sort the list?
Alphabetical order is fine, time shift order is better.
Replicate this issue on your side (need VS and a CE device)
Create an empty Smart Device project (Visual Basic)
Download OpenNetCF Community Edition (free)
Add OpenNETCF.WindowsCE.dll as Reference (right click on the project -> Add Reference)
Open Form1, add a combobox, and paste code below:
Imports OpenNETCF.WindowsCE
Public Class Form1
Private Sub Form1_Activated(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Activated
Dim tzc As New TimeZoneCollection
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
For Each tzi As TimeZoneInformation In tzc
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
End Sub
End Class

I realize my problem was a bit easy to solve. So, I found a simple way, in using the built-in Sort() method of the ArrayList.
what I do:
copy the DisplayName in an ArrayList of String
Sort it
Use it to re-index the collection of TimeZoneInformation.
My code:
Dim tzc As New TimeZoneCollection ' the raw collection'
Dim ar_s As New ArrayList() ' the array used to sort alphabetically the DisplayName'
Dim tzc_s As New TimeZoneCollection ' the sorted collection'
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
' copy the display name in an array to sort them'
For Each tzi As TimeZoneInformation In tzc
ar_s.Add(tzi.DisplayName)
Next
ar_s.Sort()
' populated tzc_s, a sorted collection of TimeZoneInformation'
For i As Integer = 0 To ar_s.Count - 1
For Each tzi As TimeZoneInformation In tzc
If ar_s(i) = tzi.DisplayName Then
tzc_s.Add(tzi)
Continue For
End If
Next
Next
' Bind the sorted ArrayList to the ComboBox'
For Each tzi As TimeZoneInformation In tzc_s
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next

I would subclass the TimeZoneCollection and add a Sort method as you alreday found but more or less implement by hand. I was not bale to verify the following as I do not have a compact framework here:
In the subclassed TimeZoneCollection add a sort method and a IComparable class. Within that class you can define whatever sort order you wich (by names, by GMT-offset...):
...
public class myTimeZoneCollection:TimeZoneCollection{
...
public class myTZIComparer : IComparer {
// return -1 for a is before b
// return +1 for a is after b
// return 0 if a is same order as b
int IComparer.Compare( Object a, Object b ) {
{
TZData c1=(TZData)a;
TZData c2=(TZData)b;
if (c1.GMTOffset > c2.GMTOffset)
return -1;//1; //this will result in reverse offset order
if (c1.GMTOffset < c2.GMTOffset)
return 1;//-1;
else
return 0;
}
}
...
public void sort(){
// Sorts the values of the ArrayList using the reverse case-insensitive comparer.
IComparer myComparer = new myTZIComparer();
this.Sort( myComparer );
}
...
}
And yes, I am sorry, this is in C# but must be do also in VB.
And, use the sorted my TimeZoneCollection to add the elements to the combobox. There is no additional work needed to get the list into the combobox in a custom sort order. Just do foreach and add.
Here is the promised full VB solution with the OpenNetCF fix:
myTimeZoneCollection.vb:
Option Strict On
Option Explicit On
Imports OpenNETCF.WindowsCE
Public Class myTimeZoneCollection
Inherits TimeZoneCollection
Dim tzc As New TimeZoneCollection
Public Sub New()
End Sub
Overloads Function Initialize() As TimeZoneCollection
tzc.Initialize()
Dim myComparer = New myTZIComparer()
tzc.Sort(myComparer)
Return tzc
End Function
Shared Function getOffsetFromDisplayName(ByVal tzi As TimeZoneInformation) As Integer
' known forms
' GMT = no offset
' GMT+6 = 6 hours offset
' GMT-12 = -6 hours offset
' GMT+4:30 = 4 hours and 30 minutes offset
' GMT-4:30 = - 4 hours and 30 minutes offset
' all these end with a space! followed by the name of the time zone
'System.Diagnostics.Debug.WriteLine("getOffsetFromDisplayName: tzi=" & tzi.ToString())
'extract offset
If (tzi.DisplayName = "GMT") Then
Return 0
End If
Dim subStr As String
subStr = tzi.DisplayName.Substring(0, tzi.DisplayName.IndexOf(" "c)) 'GMT+x or GMT-x or GMT+x:yy or GMT-x:yy
If (subStr = "GMT") Then
Return 0
End If
subStr = subStr.Substring(3) 'cut GMT from begin
'now check if this is with a minute value
Dim hoursOffset, minutesOffset, idxOfColon, idxM As Integer : idxOfColon = 0 : idxM = 0
idxOfColon = subStr.IndexOf(":"c)
If (idxOfColon = -1) Then 'no : found
hoursOffset = System.Int32.Parse(subStr)
minutesOffset = hoursOffset * 60
Else
Dim sH, sM As String
sH = subStr.Substring(0, subStr.Length - idxOfColon - 1)
sM = subStr.Substring(idxOfColon + 1)
hoursOffset = System.Int32.Parse(sH)
minutesOffset = System.Int32.Parse(sM)
If (hoursOffset > 0) Then
minutesOffset = minutesOffset + hoursOffset * 60
Else
minutesOffset = hoursOffset * 60 - minutesOffset
End If
End If
Return minutesOffset
End Function
Class myTZIComparer
Implements IComparer
'// return -1 for a is before b
'// return +1 for a is after b
'// return 0 if a is same order as b
Public Function Compare(ByVal a As Object, ByVal b As Object) As Integer Implements IComparer.Compare
Dim c1 As TimeZoneInformation = CType(a, TimeZoneInformation)
Dim c2 As TimeZoneInformation = CType(b, TimeZoneInformation)
Dim offset1, offset2 As Integer
offset1 = getOffsetFromDisplayName(c1)
offset2 = getOffsetFromDisplayName(c2)
If (offset1 > offset2) Then
Return -1 '//1; //this will result in reverse offset order
ElseIf (offset1 < offset2) Then
Return 1 '//-1;
Else 'offsets equal, sort by name
If (c1.DisplayName < c2.DisplayName) Then
Return -1
ElseIf (c1.DisplayName > c2.DisplayName) Then
Return 1
Else
Return 0
End If
End If
End Function
End Class
End Class
By changing or adding another myTZIComparer you can define the order of the entries.
The OpenNetCF code is wrong for the new timezone names
' GMT+4:30 = 4 hours and 30 minutes offset
' GMT-4:30 = - 4 hours and 30 minutes offset
as it does only look for full hour offsets. So I needed to develop a new 'parser' to get the bias data.
In your code with the listbox:
Public Sub fillList()
ComboBox1.Items.Clear()
Dim tzc As New TimeZoneCollection
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
For Each tzi As TimeZoneInformation In tzc
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
End Sub
The above fills the list in the order the items are.
Public Sub fillListGMT()
ComboBox1.Items.Clear()
Dim tzc As New myTimeZoneCollection 'subclassed one
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
Dim tzc1 As New TimeZoneCollection
tzc1.Clear()
tzc1 = tzc.Initialize()
For Each tzi As TimeZoneInformation In tzc1
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
End Sub
The code above fills the list ordered by GMT offset.

This answer is based on #Josef's idea (written in C#), and translated to VB.
This is the customized class:
Public Class myTimeZoneCollection
Inherits TimeZoneCollection
Public Class myTZIComparer
Implements IComparer
' return -1 for a is before b
' return +1 for a is after b
' return 0 if a is same order as b '
Public Function Compare(ByVal a As Object, ByVal b As Object) As Integer _
Implements IComparer.Compare
Dim c1 As TimeZoneInformation = CType(a, TimeZoneInformation)
Dim c2 As TimeZoneInformation = CType(b, TimeZoneInformation)
If (c1.Bias > c2.Bias) Then
Return -1 ' 1; //this will result in reverse offset order'
End If
If (c1.Bias < c2.Bias) Then
Return 1 ' -1;'
Else ' sort by name '
If (c1.DisplayName < c2.DisplayName) Then
Return -1
End If
If (c1.DisplayName > c2.DisplayName) Then
Return 1
Else
Return 0
End If
End If
End Function
End Class
Public Sub MySort()
' Sorts the values of the ArrayList using the specific sort Comparer (by Bias)'
Dim myComparer As IComparer = New myTZIComparer()
Me.Sort(myComparer)
End Sub
End Class
And this is the usage in the form
Private Sub Form1_Activated(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Activated
Dim tzc As New myTimeZoneCollection ' this is the customized class
Dim TheIndex As Integer ' this index is used to select the activated time zone of the system
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
tzc.MySort()
' Clear the item list otherwise it is increased at each Activated event.. '
ComboBox1.Items.Clear()
For Each tzi As TimeZoneInformation In tzc
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
End Sub
I validated this code on a device, it works fine.

Related

my program keeps failing to build because it trys to find a value in `lblUp1lvl`

my code was working fine until today when it isn't working (everthing running without errors)
and lblUp1lvl is set to 0
here is my code:
(I use the better comments extention so that's why some of the comments look funky)
Idle Time Waster.vb
Public Class formIdleTimeWaster
'*When User Loads the Program
Private Sub FormIdleTimeWaster_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODOSet cps value
Cps = 0
ClickValue = 0
timerCPS.Interval = 1000
timerCPS.Start()
'todo Update variables from save file
End Sub
'*When User Clicks the Button
Private Sub BtnUserClick_Click(sender As Object, e As EventArgs) Handles btnUserClick.Click
UserClicked()
lblTotalHW.Text = CStr(Total)
End Sub
'*Every Second this code runs
Private Sub TimerCPS_Tick(sender As Object, e As EventArgs) Handles timerCPS.Tick
AddCPS()
'Show CPS Value
lblCPS.Text = CStr(Cps)
End Sub
'?Adds 1 extra of what is meant to be added
'*User clicks Click Value upgrade button
Private Sub btnUp1_Click(sender As Object, e As EventArgs) Handles btnUp1.Click
Upgrade(Up1lvl, Up1Cost)
Up1Update()
lblUp1Cost.Text = CStr(Up1Cost)
lblUp1lvl.Text = CStr(Up1lvl)
lblClickValue.Text = CStr(Up1lvl)
End Sub
'*User clicks CPS upgrade value
Private Sub btnUp2_Click(sender As Object, e As EventArgs) Handles btnUp2.Click
Upgrade(Up2lvl, Up2Cost)
Up2Update()
lblUp2Cost.Text = CStr(Up2Cost)
lblUp2lvl.Text = CStr(Up2lvl)
lblCPS.Text = CStr(Up2lvl)
End Sub
End Class
Functions.vb
Public Module Functions
'*Define All Needed Values
Public Total As Integer
Public Cps As Integer
Public ClickValue As Integer
Public Up1lvl As Integer = 0
Public Up1Cost As Integer
Public Up2lvl As Integer = 0
Public Up2Cost As Integer
'*When User Clicks the Button
Function UserClicked()
Total = ClickValue + Total
Return Total
End Function
'*Calculate Cps
Function AddCPS()
'Add Cps to HWTotal
Total = Total + Cps
Return Total
End Function
'*Upgrade
Sub Upgrade(ByRef lvl, ByRef Cost)
If Total >= Cost Then
Total = CInt(Total) - Cost
lvl = lvl + 1
Else
MsgBox("Not Enough time wasted, go do nothing some more to get better at doing nothing", 0, "to early!")
End If
End Sub
'FIXME:the program seems to have difficulty when i try to bring ``Up1Cost`` and ``Up2Cost`` into the function
'*xUpdate Upgrade Values
'xFunction Update(ByRef Cost As Integer, ByRef lvl As Integer, ByRef Value As Integer)
'x Cost = lvl * 10
'x Value = lvl
'xReturn Cost & lvl & Value
'xEnd Function
'*Update Click Value Upgrade Values
Sub Up1Update()
Up1Cost = Up1lvl * 10
ClickValue = Up1lvl
End Sub
'*Update CPS Upgrade Values
Sub Up2Update()
Up2Cost = Up2lvl * 10
Cps = Up2lvl
End Sub
End Module
Idle Time Waster.Designer.vb
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class formIdleTimeWaster
Inherits System.Windows.Forms.Form
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
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.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container()
Dim gbStats As System.Windows.Forms.GroupBox
Dim lblHWPerClickTitle As System.Windows.Forms.Label
Dim lblCPSTitle As System.Windows.Forms.Label
Dim lblTotalHWTitle As System.Windows.Forms.Label
Dim lblUp1lvlName As System.Windows.Forms.Label
Dim lblUp2lvlName As System.Windows.Forms.Label
Dim lblUp1CostName As System.Windows.Forms.Label
Dim lblUp2CostName As System.Windows.Forms.Label
Me.lblClickValue = New System.Windows.Forms.Label()
Me.lblCPS = New System.Windows.Forms.Label()
Me.lblTotalHW = New System.Windows.Forms.Label()
Me.btnUserClick = New System.Windows.Forms.Button()
Me.timerCPS = New System.Windows.Forms.Timer(Me.components)
Me.lblUp2lvl = New System.Windows.Forms.Label()
Me.btnUp1 = New System.Windows.Forms.Button()
Me.btnUp2 = New System.Windows.Forms.Button()
Me.lblUp1Cost = New System.Windows.Forms.Label()
Me.lblUp2Cost = New System.Windows.Forms.Label()
Me.NotifyIcon1 = New System.Windows.Forms.NotifyIcon(Me.components)
Me.lblUp1lvl = New System.Windows.Forms.Label()
gbStats = New System.Windows.Forms.GroupBox()
lblHWPerClickTitle = New System.Windows.Forms.Label()
lblCPSTitle = New System.Windows.Forms.Label()
lblTotalHWTitle = New System.Windows.Forms.Label()
lblUp1lvlName = New System.Windows.Forms.Label()
lblUp2lvlName = New System.Windows.Forms.Label()
lblUp1CostName = New System.Windows.Forms.Label()
lblUp2CostName = New System.Windows.Forms.Label()
gbStats.SuspendLayout()
Me.SuspendLayout()
'
'gbStats
'
gbStats.Controls.Add(Me.lblClickValue)
gbStats.Controls.Add(Me.lblCPS)
gbStats.Controls.Add(Me.lblTotalHW)
gbStats.Controls.Add(lblHWPerClickTitle)
gbStats.Controls.Add(lblCPSTitle)
gbStats.Controls.Add(lblTotalHWTitle)
gbStats.Location = New System.Drawing.Point(217, 8)
gbStats.Name = "gbStats"
gbStats.Size = New System.Drawing.Size(208, 114)
gbStats.TabIndex = 0
gbStats.TabStop = False
gbStats.Text = "Stats"
'
'lblClickValue
'
Me.lblClickValue.AutoSize = True
Me.lblClickValue.CausesValidation = False
Me.lblClickValue.Location = New System.Drawing.Point(153, 82)
Me.lblClickValue.Name = "lblClickValue"
Me.lblClickValue.Size = New System.Drawing.Size(13, 15)
Me.lblClickValue.TabIndex = 5
Me.lblClickValue.Text = "0"
'
'lblCPS
'
Me.lblCPS.AutoSize = True
Me.lblCPS.Location = New System.Drawing.Point(166, 52)
Me.lblCPS.Name = "lblCPS"
Me.lblCPS.Size = New System.Drawing.Size(13, 15)
Me.lblCPS.TabIndex = 4
Me.lblCPS.Text = "0"
'
'lblTotalHW
'
Me.lblTotalHW.AutoSize = True
Me.lblTotalHW.CausesValidation = False
Me.lblTotalHW.Location = New System.Drawing.Point(132, 21)
Me.lblTotalHW.Name = "lblTotalHW"
Me.lblTotalHW.Size = New System.Drawing.Size(13, 15)
Me.lblTotalHW.TabIndex = 3
Me.lblTotalHW.Text = "0"
'
'lblHWPerClickTitle
'
lblHWPerClickTitle.AutoSize = True
lblHWPerClickTitle.Location = New System.Drawing.Point(14, 82)
lblHWPerClickTitle.Name = "lblHWPerClickTitle"
lblHWPerClickTitle.Size = New System.Drawing.Size(133, 15)
lblHWPerClickTitle.TabIndex = 2
lblHWPerClickTitle.Text = "Hours Wasted Per Click:"
'
'lblCPSTitle
'
lblCPSTitle.AutoSize = True
lblCPSTitle.Location = New System.Drawing.Point(14, 52)
lblCPSTitle.Name = "lblCPSTitle"
lblCPSTitle.Size = New System.Drawing.Size(146, 15)
lblCPSTitle.TabIndex = 1
lblCPSTitle.Text = "Hours Wasted per Second:"
'
'lblTotalHWTitle
'
lblTotalHWTitle.AutoSize = True
lblTotalHWTitle.Location = New System.Drawing.Point(14, 21)
lblTotalHWTitle.Name = "lblTotalHWTitle"
lblTotalHWTitle.Size = New System.Drawing.Size(112, 15)
lblTotalHWTitle.TabIndex = 0
lblTotalHWTitle.Text = "Total Hours Wasted:"
'
'lblUp1lvlName
'
lblUp1lvlName.AutoSize = True
lblUp1lvlName.Location = New System.Drawing.Point(217, 149)
lblUp1lvlName.Name = "lblUp1lvlName"
lblUp1lvlName.Size = New System.Drawing.Size(37, 15)
lblUp1lvlName.TabIndex = 2
lblUp1lvlName.Text = "Level:"
'
'lblUp2lvlName
'
lblUp2lvlName.AutoSize = True
lblUp2lvlName.Location = New System.Drawing.Point(217, 175)
lblUp2lvlName.Name = "lblUp2lvlName"
lblUp2lvlName.Size = New System.Drawing.Size(37, 15)
lblUp2lvlName.TabIndex = 4
lblUp2lvlName.Text = "Level:"
'
'lblUp1CostName
'
lblUp1CostName.AutoSize = True
lblUp1CostName.Location = New System.Drawing.Point(291, 149)
lblUp1CostName.Name = "lblUp1CostName"
lblUp1CostName.Size = New System.Drawing.Size(34, 15)
lblUp1CostName.TabIndex = 8
lblUp1CostName.Text = "Cost:"
'
'lblUp2CostName
'
lblUp2CostName.AutoSize = True
lblUp2CostName.Location = New System.Drawing.Point(291, 175)
lblUp2CostName.Name = "lblUp2CostName"
lblUp2CostName.Size = New System.Drawing.Size(34, 15)
lblUp2CostName.TabIndex = 9
lblUp2CostName.Text = "Cost:"
'
'btnUserClick
'
Me.btnUserClick.Location = New System.Drawing.Point(12, 12)
Me.btnUserClick.Name = "btnUserClick"
Me.btnUserClick.Size = New System.Drawing.Size(199, 110)
Me.btnUserClick.TabIndex = 1
Me.btnUserClick.Text = "Play Idle Game"
Me.btnUserClick.UseVisualStyleBackColor = True
'
'timerCPS
'
'
'lblUp2lvl
'
Me.lblUp2lvl.AutoSize = True
Me.lblUp2lvl.Location = New System.Drawing.Point(260, 175)
Me.lblUp2lvl.Name = "lblUp2lvl"
Me.lblUp2lvl.Size = New System.Drawing.Size(13, 15)
Me.lblUp2lvl.TabIndex = 5
Me.lblUp2lvl.Text = "0"
'
'btnUp1
'
Me.btnUp1.Location = New System.Drawing.Point(12, 143)
Me.btnUp1.Name = "btnUp1"
Me.btnUp1.Size = New System.Drawing.Size(199, 27)
Me.btnUp1.TabIndex = 6
Me.btnUp1.Text = "Upgrade Click"
Me.btnUp1.UseVisualStyleBackColor = True
'
'btnUp2
'
Me.btnUp2.Location = New System.Drawing.Point(12, 169)
Me.btnUp2.Name = "btnUp2"
Me.btnUp2.Size = New System.Drawing.Size(199, 27)
Me.btnUp2.TabIndex = 7
Me.btnUp2.Text = "Upgrade Passive time wasting"
Me.btnUp2.UseVisualStyleBackColor = True
'
'lblUp1Cost
'
Me.lblUp1Cost.AutoSize = True
Me.lblUp1Cost.Location = New System.Drawing.Point(330, 149)
Me.lblUp1Cost.Name = "lblUp1Cost"
Me.lblUp1Cost.Size = New System.Drawing.Size(13, 15)
Me.lblUp1Cost.TabIndex = 10
Me.lblUp1Cost.Text = "0"
'
'lblUp2Cost
'
Me.lblUp2Cost.AutoSize = True
Me.lblUp2Cost.CausesValidation = False
Me.lblUp2Cost.Location = New System.Drawing.Point(331, 175)
Me.lblUp2Cost.Name = "lblUp2Cost"
Me.lblUp2Cost.Size = New System.Drawing.Size(13, 15)
Me.lblUp2Cost.TabIndex = 11
Me.lblUp2Cost.Text = "0"
'
'NotifyIcon1
'
Me.NotifyIcon1.Text = "NotifyIcon1"
Me.NotifyIcon1.Visible = True
'
'lblUp1lvl
'
Me.lblUp1lvl.AutoSize = True
Me.lblUp1lvl.Location = New System.Drawing.Point(260, 149)
Me.lblUp1lvl.Name = "lblUp1lvl"
Me.lblUp1lvl.Size = New System.Drawing.Size(13, 15)
Me.lblUp1lvl.TabIndex = 12
Me.lblUp1lvl.Text = "0"
'
'formIdleTimeWaster
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(7.0!, 15.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(440, 207)
Me.Controls.Add(Me.lblUp1lvl)
Me.Controls.Add(Me.lblUp2Cost)
Me.Controls.Add(Me.lblUp1Cost)
Me.Controls.Add(lblUp2CostName)
Me.Controls.Add(lblUp1CostName)
Me.Controls.Add(Me.btnUp2)
Me.Controls.Add(Me.btnUp1)
Me.Controls.Add(Me.lblUp2lvl)
Me.Controls.Add(lblUp2lvlName)
Me.Controls.Add(lblUp1lvlName)
Me.Controls.Add(Me.btnUserClick)
Me.Controls.Add(gbStats)
Me.Name = "formIdleTimeWaster"
Me.Text = "Idle Time Waster"
gbStats.ResumeLayout(False)
gbStats.PerformLayout()
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Friend WithEvents gbStats As GroupBox
Friend WithEvents lblHWPerClickTitle As Label
Friend WithEvents lblCPSTitle As Label
Friend WithEvents lblTotalHWTitle As Label
Friend WithEvents btnUserClick As Button
Friend WithEvents lblTotalHW As Label
Friend WithEvents lblCPS As Label
Friend WithEvents timerCPS As Timer
Friend WithEvents lblUp1lvlName As Label
Friend WithEvents lblUp2lvlName As Label
Friend WithEvents lblUp2lvl As Label
Friend WithEvents btnUp1 As Button
Friend WithEvents btnUp2 As Button
Friend WithEvents lblUp1CostName As Label
Friend WithEvents lblUp2CostName As Label
Friend WithEvents lblUp1Cost As Label
Friend WithEvents lblUp2Cost As Label
Friend WithEvents NotifyIcon1 As NotifyIcon
Friend WithEvents lblClickValue As Label
Friend WithEvents lblUp1lvl As Label
End Class
this error comes up when i build it:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Idle_time_Waster.formIdleTimeWaster.lblUp1lvl.get returned Nothing
as of posting this question am going to try seeing if updating VS fixes the problem

Iterate through a treeview in VB6

I have a treeview control on the form which looks like:
I want to iterate the treeview and write the contents of the treeview to ini file. So the ini file for the given tree would look like:
[EnvironmentSystem]
UpdateRate=50.0
InclinationAngle=20.7
Latitude=34.0
[Reflection]
NumReflectionLevel=5
NumSunLightLevel=5
NumWeatherLevel=3
TextureNameFormat=Reflection%01d%01d%02d.tga
[CloudsClear]
MaxClouds=48
MaxCloudParticles=51
3DCloudMaterial=CloudMaterial
3DCloudHorizontalSize=1400.0
3DCloudVerticalSize=600.0
3DCloudSizeDeviation=0.6
3DCloudParticleDensity=2.4
ParticleSize=300.0
ParticleSizeDeviation=0.3
MinBaseAltitude=400.0
MaxBaseAltitude=2450.0
UseBottomRow=TRUE
Here is the code that I have written:
Private Sub TvSaveToIniBtn_Click()
Dim nodx As Node
Dim i As Long
Dim sectionCount As Integer
sectionCount = TreeView1.Nodes(1).Children
Set nodx = TreeView1.Nodes(1).Child.FirstSibling
For i = 1 To sectionCount
SaveNodesToIni (nodx.Text)
Set nodx = nodx.Next
Next
End Sub
Sub SaveNodesToIni(sName As Variant)
Dim tvn As Node
Set tvn = TreeView1.Nodes(sName)
Dim chil As Integer
Dim a As Integer
Dim ret As Integer
Dim keyValuePair() As String
Dim nElements As Integer
chil = tvn.Children: If chil = 0 Then Exit Sub ' if no children the exit
Set tvn = tvn.Child.FirstSibling
For a = 1 To chil
keyValuePair = Split(tvn.Text, "=")
nElements = UBound(keyValuePair) - LBound(keyValuePair) + 1
If nElements > 0 Then
ret = WritePrivateProfileString(sName, keyValuePair(0), keyValuePair(1), "C:\\MyPrograms\\config.ini")
End If
Set tvn = tvn.Next
Next
End Sub
It is not giving the correct output, it gets stuck at the second section of reflection and is not able to read the third one. Something wrong with the code.

Mouse Move Handle on a ListBox

I have a ListBox on which I want to handle the mousemove event; And for that reason I'm using the following code
Private Sub AreaLB_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles AreaLB.MouseMove
Dim ListMousePosition As Point = AreaLB.PointToClient(Me.MousePosition)
Dim itemIndex As Integer = AreaLB.IndexFromPoint(ListMousePosition)
Dim AreaToolTip As ToolTip = ToolTip1
Dim myLB As ListBox = AreaLB
AreaToolTip.Active = True
Dim g As Graphics = AreaLB.CreateGraphics()
If itemIndex > -1 Then
Dim s As String = myLB.Items(itemIndex)
If g.MeasureString(s, myLB.Font).Width > myLB.ClientRectangle.Width Then
AreaToolTip.SetToolTip(myLB, s)
Else
AreaToolTip.SetToolTip(myLB, "")
End If
g.Dispose()
End If
End Sub
My problem is... When I'm not moving the mouse this procedure runs always when the
g.MeasureString(s, myLB.Font).Width > myLB.ClientRectangle.Width
Why that happens and how can I avoid it.
What you can do is only set the ToolTip if it isn't already the value you want it to be:
Private Sub AreaLB_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles AreaLB.MouseMove
ToolTip1.Active = True
Dim itemIndex As Integer = AreaLB.IndexFromPoint(e.X, e.Y)
If itemIndex > -1 Then
Using g As Graphics = AreaLB.CreateGraphics()
Dim s As String = AreaLB.Items(itemIndex)
If g.MeasureString(s, AreaLB.Font).Width > AreaLB.ClientRectangle.Width Then
If ToolTip1.GetToolTip(AreaLB) <> s Then
ToolTip1.Show(s, AreaLB)
End If
Else
ToolTip1.Show("", AreaLB)
End If
End Using
End If
End Sub

Visual Studio macro to collapse custom nodes

If I were to have something like:
namespace SomeNameSpace
{
#region Usings
using System.Collections.Generic;
using System.Security;
#endregion
/// <summary> Implements a dictionary with several keys. </summary>
/// <typeparam name="Value"> What type of elements we will be storing in the dictionary</typeparam>
public class MultiKeyDic<Value>
{
/// <summary> a very long summary that can be
/// collapsed and expanded. </summary>
public int SomeInt {get;set;}
public void someMethod()
{
}
}
}
How can I create a macro that will find all the places that can be expandable (Nodes). If I would like to collapse all the nodes I will have to collapse the nodes in the order of someMethod(), summary of SomeInt , class MultiKeyDic, summary of class MultiKeyDic, #region Usings and finally namespace.
I know the command ctrl+M+O collapses everything, but I do not want to collapse everything. For example I might not want to collapse the comments. If I collapse everything and then expand the comments that expands the parent node too.
So far I have created this macro that will find most of the nodes:
Sub VisitAllNodes()
Dim i As Integer
Dim fileCM As FileCodeModel
Dim elts As EnvDTE.CodeElements
Dim elt As EnvDTE.CodeElement
fileCM = DTE.ActiveDocument.ProjectItem.FileCodeModel
elts = fileCM.CodeElements
For i = 1 To elts.Count
elt = elts.Item(i)
CollapseE(elt, elts, i)
Next
End Sub
'' Helper to OutlineCode. Recursively outlines members of elt.
''
Sub CollapseE(ByVal elt As EnvDTE.CodeElement, ByVal elts As EnvDTE.CodeElements, ByVal loc As Integer)
Dim epStart As EnvDTE.EditPoint
Dim epEnd As EnvDTE.EditPoint
epStart = elt.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint()
epEnd = elt.GetEndPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint() ' Copy it because we move it later.
epStart.EndOfLine()
If ((elt.IsCodeType()) And (elt.Kind <> EnvDTE.vsCMElement.vsCMElementDelegate)) Then
Dim i As Integer
Dim mems As EnvDTE.CodeElements
mems = elt.Members
For i = 1 To mems.Count
Dim temp As EnvDTE.CodeElement = mems.Item(i)
Dim t As String = [Enum].GetName(GetType(EnvDTE.vsCMElement), temp.Kind)
MsgBox("Found member (" & t & ") at line# " & temp.StartPoint.Line)
CollapseE(mems.Item(i), mems, i)
Next
ElseIf (elt.Kind = EnvDTE.vsCMElement.vsCMElementNamespace) Then
Dim i As Integer
Dim mems As EnvDTE.CodeElements
mems = elt.Members
For i = 1 To mems.Count
Dim temp As EnvDTE.CodeElement = mems.Item(i)
Dim t As String = [Enum].GetName(GetType(EnvDTE.vsCMElement), temp.Kind)
MsgBox("Found member (" & t & ") at line# " & temp.StartPoint.Line)
CollapseE(mems.Item(i), mems, i)
Next
End If
'Return
' collapse the element
If (epStart.LessThan(epEnd)) Then
loc = loc + 1
If (loc <= elts.Count) Then
epEnd.MoveToPoint(elts.Item(loc).GetStartPoint(vsCMPart.vsCMPartHeader))
epEnd.LineUp()
epEnd.EndOfLine()
End If
epStart.OutlineSection(epEnd)
End If
End Sub
It looks more complicated than what it is. Run it on any document and it will display all the properties, classes, enums, etc., but for some reason it does not find the comments nor regions.
the first Function IncludeMember is used to determine what type of members to exclude. for example in this example I do not collapse namespaces and using directives:
' filter some mebers. for example using statemets cannot be collapsed so exclude them.
Function IncludeMember(ByVal member As EnvDTE.CodeElement)
If member.Kind = vsCMElement.vsCMElementIDLImport Then
Return False
ElseIf member.Kind = vsCMElement.vsCMElementNamespace Then
Return False ' I do not want to colapse enums
End If
Return True
End Function
Sub CollapseNodes()
' activate working window
DTE.Windows.Item(DTE.ActiveDocument.Name).Activate()
' expand everything to start
Try
DTE.ExecuteCommand("Edit.StopOutlining")
Catch
End Try
Try
DTE.ExecuteCommand("Edit.StartAutomaticOutlining")
Catch
End Try
' get text of document and replace all new lines with \r\n
Dim objTextDoc As TextDocument
Dim objEditPt As EnvDTE.EditPoint
Dim text As String
' Get a handle to the new document and create an EditPoint.
objTextDoc = DTE.ActiveDocument.Object("TextDocument")
objEditPt = objTextDoc.StartPoint.CreateEditPoint
' Get all Text of active document
text = objEditPt.GetText(objTextDoc.EndPoint)
text = System.Text.RegularExpressions.Regex.Replace( _
text, _
"(\r\n?|\n\r?)", ChrW(13) & ChrW(10) _
)
' add new line to text so that lines of visual studio match with index of array
Dim lines As String() = System.Text.RegularExpressions.Regex.Split(vbCrLf & text, vbCrLf)
' list where whe will place all colapsable items
Dim targetLines As New System.Collections.Generic.List(Of Integer)
' regex that we will use to check if a line contains a #region
Dim reg As New System.Text.RegularExpressions.Regex(" *#region( |$)")
Dim i As Integer
For i = 1 To lines.Length - 1
If reg.Match(lines(i)).Success Then
targetLines.Add(i)
End If
Next
Dim fileCM As FileCodeModel
Dim elts As EnvDTE.CodeElements
Dim elt As EnvDTE.CodeElement
Dim projectItem = DTE.ActiveDocument.ProjectItem
Dim temp = projectItem.Collection.Count
Dim b = DirectCast(DirectCast(projectItem.Document, EnvDTE.Document).ActiveWindow, EnvDTE.Window).ContextAttributes
fileCM = projectItem.FileCodeModel
elts = fileCM.CodeElements
For i = 1 To elts.Count
elt = elts.Item(i)
CollapseE(elt, elts, i, targetLines)
Next
' now that we have the lines that we will plan to collapse sort them. it is important to go in order
targetLines.Sort()
ActivateWorkingWindow()
' go in reverse order so that we can collapse nested regions
For i = targetLines.Count - 1 To 0 Step -1
DTE.ExecuteCommand("Edit.Goto", targetLines(i))
DTE.ExecuteCommand("Edit.ToggleOutliningExpansion")
Next
End Sub
'' Helper to OutlineCode. Recursively outlines members of elt.
''
Sub CollapseE(ByVal elt As EnvDTE.CodeElement, ByVal elts As EnvDTE.CodeElements, ByVal loc As Integer, ByRef targetLines As System.Collections.Generic.List(Of Integer))
Dim epStart As EnvDTE.EditPoint
Dim epEnd As EnvDTE.EditPoint
epStart = elt.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint()
epEnd = elt.GetEndPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint() ' Copy it because we move it later.
epStart.EndOfLine()
If ((elt.IsCodeType()) And (elt.Kind <> EnvDTE.vsCMElement.vsCMElementDelegate) Or elt.Kind = EnvDTE.vsCMElement.vsCMElementNamespace) Then
Dim i As Integer
Dim mems As EnvDTE.CodeElements
mems = elt.Members
For i = 1 To mems.Count
CollapseE(mems.Item(i), mems, i, targetLines)
Next
End If
If (epStart.LessThan(epEnd)) Then
If IncludeMember(elt) Then
targetLines.Add(epStart.Line)
End If
End If
End Sub

MS Visual Basic how to sort 1 array and return index for second array?

the language I am looking is MS Visual Basic.
How can I sort an array and change other arrays accordingly (using an index?)
I was searching, but couldnt find any stuff on that. Any help is greatly appreciated!!!
e.g. Sort array BirthArray and change the order of Array1 and ID accordingly?
Array1 = 'John', 'Christina','Mary', 'frediric', 'Johnny','billy','mariah'
BirthArray = 1998, 1923, 1983,1982,1924,1923,1954
ID = 12312321, 1231231209, 123123, 234324, 23423, 2234234,932423
Dim Array() As String
Dim BirthArray() As Integer
Dim ID() As Integer
Thanks a lot!
You should make a class to hold the values, put a collection of the classes into a List, then sort the the list using a lambda expression:
Public Class Info
Public Property Name As String
Public Property BirthYear As Integer
Public Property ID As Integer
Public Sub New()
End Sub
Public Sub New(sName As String, wBirthYear As Integer, wID As Integer)
Me.New
Me.Name = sName
Me.BirthYear = wBirthYear
Me.ID = wID
End Sub
End Class
Public Sub DoSort()
Dim cRecords As New System.Generic.List(Of Info)
cRecords.Add(New Info('John', 1998, 12312321)
' ToDo: Add more records
cRecords.Sort(
Function (ByVal oItem1 As Info, ByVal oItem2 As Info)
Return oItem2.BirthYear.CompareTo(oItem1.BirthYear)
End Function)
End Sub
The proposed soluton below (based on your VBA tag).
creates a 2D array from 3 single arrays (as suggested by Jesse)
uses Redim Preserve to add a fourth dataset "NewData" to a 2D array "ArrayMaster"
creates a temporary worksheet, dumps "ArrayMaster" to it, sorts by "Newdata" (ascending order) to create a sorted array, "ArrayMaster2"
deletes the working sheet
Excel is very efficient at sorting, so this method provided an easy and quick way for a sort (or multi level sort)
You could use a bubble sort technique if Excel wasn't available for the sheet dump/sort
Option Base 1
Sub ComboArray()
Dim ws As Worksheet
Dim Array1()
Dim Birthday()
Dim ID()
Dim NewData()
Dim ArrayMaster()
Dim ArrayMaster2()
Dim lngRow As Long
Dim lngCalc As Long
Dim lngCheck As Long
Birthday = Array(1998, 1923, 1983, 1982, 1924, 1923, 1954)
Array1 = Array("John", "Christina", "Mary", "frediric", "Johnny", "billy", "mariah")
ID = Array(12312321, 1231231209, 123123, 234324, 23423, 2234234, 932423)
ReDim ArrayMaster(1 To UBound(Array1, 1), 1 To 3)
'Create 2D MasterArray
For lngRow = 1 To UBound(Array1, 1)
ArrayMaster(lngRow, 1) = Array1(lngRow)
ArrayMaster(lngRow, 2) = Birthday(lngRow)
ArrayMaster(lngRow, 3) = ID(lngRow)
Next
NewData = Array(1, 3, 5, 7, 2, 4, 6)
'Check if new field is longer than overall array
If UBound(NewData, 1) > UBound(ArrayMaster, 1) Then
lngCheck = MsgBox("New field exceeds current array size, proceeding will drop off excess records" & vbNewLine & "(Press Cancel to end code)", vbOKCancel, "Do you want to proceed?")
If lngCheck = vbCancel Then Exit Sub
End If
'Add NewData field
ReDim Preserve ArrayMaster(UBound(ArrayMaster, 1), UBound(ArrayMaster, 2) + 1)
For lngRow = 1 To UBound(NewData, 1)
ArrayMaster(lngRow, UBound(ArrayMaster, 2)) = NewData(lngRow)
Next
With Application
.ScreenUpdating = False
.DisplayAlerts = False
lngCalc = .Calculation
End With
'Create working sheet, dump MasterArray and sort by Newdata (position 4 = cell D1)
Set ws = Worksheets.Add
ws.[a1].Resize(UBound(ArrayMaster, 1), UBound(ArrayMaster, 2)).Value2 = ArrayMaster
ws.UsedRange.Sort ws.[d1], xlAscending
'Create our sorted array MasterArray2, now with NewData(1,2,3,4,5,6,7)
ArrayMaster2 = ws.[a1].Resize(UBound(ArrayMaster, 1), UBound(ArrayMaster, 2)).Value2
ws.Delete
'cleanup working sheet
With Application
.ScreenUpdating = True
.DisplayAlerts = True
.Calculation = lngCalc
End With
End Sub

Resources