Dictionary doesn't display Items for certain Key (Numeric value)

浪子不回头ぞ 提交于 2020-01-11 10:29:28

问题


This is a Long one, but stay with me...

I have a Dictionary that saves "PO" as Key and "SO" as Items (there can be cases that a certain "PO" has multiple "SO".

My Excel data in a worksheet, where the Dictionary get's his values looks like this:

The code for populating the Dictionary (working) looks like this:

Option Explicit

Const OrdersDBShtName               As String = "Orders_DB"
Public OrdersDBSht                  As Worksheet
Public LastSORow                    As Long
Public PODict                       As Object ' Public Dictionay for PO#, and keep SO per PO# (unique ID)

'======================================================================
Sub InitDict()

Dim AdminSht                        As Worksheet
Dim i As Long, j As Long

' set the sheet object where the "Orders_DB" data lies
On Error Resume Next
Set OrdersDBSht = ThisWorkbook.Worksheets(OrdersDBShtName)
On Error GoTo 0
If OrdersDBSht Is Nothing Then ' in case someone renamed the "Admin" Sheet
    MsgBox Chr(34) & OrdersDBShtName & Chr(34) & " Sheet has been renamed, please modify it", vbCritical
    End
End If

With OrdersDBSht
    LastSORow = .Cells(.Rows.Count, "B").End(xlUp).Row ' get last row with data in column "B" ("SO#")

    ' get all SO numbers in Dictionary (SO# is unique ID)
    Set SODict = CreateObject("Scripting.Dictionary")

    ' get all PO's in Dictionary (PO# is unique, but there can be several SO# per PO#)
    Set PODict = CreateObject("Scripting.Dictionary")
    Dim ID As Variant, Names As String

    ' add unique Category values to Dictionary object , and save Item Names in Names
    For i = 2 To LastSORow
        If Not PODict.Exists(.Range("A" & i).Value) Then
            ID = .Range("A" & i).Value

            For j = 2 To LastSORow
                If .Range("A" & j).Value = ID Then
                    If Names = "" Then
                        Names = .Range("B" & j).Value  ' get the SO#
                    Else
                        Names = Names & "," & .Range("B" & j).Value  ' get the SO#
                    End If
                End If
            Next j
            PODict.Add ID, Names
        End If
        ID = Empty
        Names = Empty
    Next i

    ' section below for DEBUG Only (works)
    Dim Key As Variant
    For Each Key In PODict.keys
       Debug.Print Key & " | " & PODict(Key)
    Next Key
End With

End Sub

The Problem: I have a User_Form with 2 ListBoxes.

  1. ExistingPO_LB - a ListBox for "PO"s, reads all the Unique Keys in the Dictionary object.
  2. ExistingSO_LB - a ListBox for "SO#", should show only Items for the Key selected in ExistingPO_LB.

In some cases (like the screen-shot below) it works:

In some cases (like the screen-shot below) it doesn't (even though the Items have been saved correctly in PODict Dictionary object):

User_Form Code

Private Sub EditSO_Btn_Click()

With Me.ExistingSO_LB
    For i = 0 To .ListCount - 1
        If .Selected(i) Then
            EditSONumer = .List(i)
            Exit For
        End If
    Next i
End With

If EditSONumer = 0 Then
    MsgBox "No SO was selected from the list", vbInformation
    Exit Sub
End If

Unload Me
AddEdit_Orders_Form.Show  ' call sub Edit Order (load Add Order with the SO# data requested)

End Sub

'=========================================================
Private Sub ExistingPO_LB_Click()
' ****** This is the Sub I guess I'm missing something ******

Dim i As Long
Dim POSelected  As Variant
Dim SOArr       As Variant

With Me.ExistingPO_LB
    For i = 0 To .ListCount - 1
        If .Selected(i) Then
            POSelected = .List(i)
            Exit For
        End If
    Next i
End With

' update the SO listbox with only relevant SO (from the selected PO)
SOArr = Split(PODict(POSelected), ",") '<=== PODict(POSelected) return empty ???
With Me.ExistingSO_LB
    .Clear ' clear the previous items        
    For i = LBound(SOArr) To UBound(SOArr)
        .AddItem SOArr(i)
    Next i
End With

End Sub

'=========================================================
Private Sub UserForm_Initialize()
' load all existing PO's from "Orders DB" sheet

Dim Key As Variant

' populate listbox with PO's
With Me.ExistingPO_LB
    For Each Key In PODict.keys
        .AddItem Key
    Next Key
End With

End Sub

回答1:


The numeric keys were entered as numbers and you are fetching them as strings. I suggest that you stick to one convention for your dictionary.

Sub TestDict()
  Dim dict As New Dictionary
  dict.Add 1, "one"
  dict.Add "2", "two"

  Debug.Print dict("1")     ' Nothing
  Debug.Print dict(1)       ' one

  Debug.Print dict("2")    ' two
  Debug.Print dict(2)      ' Nothing
End Sub

Solution

Chose a convention for your dictionary and stick to it. In this application I would take the convention of always converting my keys to strings, both when inserting and when fetching. A few changes in your code can achieve it:

If Not PODict.Exists(CStr(Range("A" & i).Value) Then ' could use .Text also

PODict.Add CStr(ID), Names


SOArr = Split(PODict(CStr(POSelected)), ",") ' maybe not needed here, but to illustrate


来源:https://stackoverflow.com/questions/44787615/dictionary-doesnt-display-items-for-certain-key-numeric-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!