VB.Net 2010“未将对象引用设置为对象的实例”当使用列表作为值从字典声明变量时

问题描述

这是一个学校的编程项目(不是评估或作业,所以我没有作弊),我必须制作一个 7 段显示来源 1。我决定不采用传统方式,而是手动将每个 RectangeShape 设置为在按下的每个按钮上可见以显示数字;将相应的数字和要打开的 RectangleShape(s) 作为键值对存储在字典中。我对 Python 有一些了解,所以这就是我的想法的来源。我的表单Source 2 有 7 RectangleShape(s) 和 10 Button(s)。作为一个实验,因为这是我第一次在 Dictionaries 中使用 ListsVB.net,所以我决定现在只尝试使用数字 1({{1 }} 和 shp4 应该是可见的)。这是我编的字典:

shp5

这是按钮 (Dim Numbers As New Dictionary(Of Integer,List(Of PowerPacks.Shape)) From {{1,New List(Of PowerPacks.Shape) From {shp4,shp5}},{2,New List(Of PowerPacks.Shape) From {shp2,shp3}}} ) 的代码

btn1

当程序到达 Private Sub btn1_Click(ByVal sender As System.Object,ByVal e As System.EventArgs) Handles btn1.Click Dim Thing As PowerPacks.Shape = Numbers(1)(0) Thing.Visible = True End Sub 行时,它抛出一个错误。这是一个 Thing.Visible = True 说明 NullReferenceException 关于如何解决这个问题的任何想法?

来源

来源 1:

Image of a 7-Segment Display

来源 2:

My 7-Segment Display Visual Basic Form

解决方法

编程不是魔术。它的工作原理与您期望的差不多。如果您在 Nothing 中从 List 中取出 Dictionary,那么您必须放入 Nothing。您在发布前是否使用了调试器?执行此行时,您是否实际查看了 shp2 等的值:

Dim Numbers As New Dictionary(Of Integer,List(Of PowerPacks.Shape)) From {{1,New List(Of PowerPacks.Shape) From {shp4,shp5}},{2,New List(Of PowerPacks.Shape) From {shp2,shp3}}}

基于你在第二个代码片段中使用的那个 Numbers 变量,它必须是一个成员变量,这意味着第一个代码片段在任何方法之外,这意味着它在类构造函数之前执行,这意味着当时没有创建任何控件,这意味着任何引用控件的字段只能是 Nothing。如果您在该行上放置了一个断点并使用了调试器,那么您就会看到这一点。

解决方案实际上并不是在创建集合之前将 Shapes 添加到集合中。这意味着在调用 InitializeComponent 之后。这意味着您可以创建自己的构造函数并根据需要在那里执行此操作,但您可能应该只在 Load 事件处理程序中执行此操作。只需声明 Dictionary 变量而不创建对象:

Private numbers As Dictionary(Of Integer,PowerPacks.Shape())

请注意,我提供了一个明确的访问修饰符,您应该始终为所有成员执行此操作,并且还以小写字母开头的名称,您可能应该为所有私有字段执行此操作。然后在 load 事件处理程序中创建对象:

numbers As New Dictionary(Of Integer,PowerPacks.Shape()) From {{1,{shp4,{shp2,shp3}}}

我冒昧地通过使用数组而不是 Lists 来简化它。

,

在您的 7 段显示表单上,我将使用 List (of String) 包含为每个字典键(数字)打开的矩形。这需要首先以编程方式将 7 个形状添加到表单上(看起来您已经对其进行了编码),然后在每个按钮(对于数字)中选择打开哪些矩形并更改它们的背景颜色。 “前端加载”所有形状(矩形)到字典中可能是不必要的,因为它们已经手动固定在表单上。如果不是,则取出将它们放置在表单上的代码,并在表单加载时首先运行该代码。使用这种方法,您不必再担心形状。

在表格 1 中,添加:

Dim dicRSBackColor As New Dictionary(Of Integer,List(Of String))
Dim SC As New ShapeContainer

在 Form1_Load 中,添加以下内容:

   'define each of the 7 rectangles using,e.g.: 
    Dim myrec4 As New RectangleShape
    myrec4.Name = "shp4"
    myrec4.Visible = True
    myrec4.BringToFront()
    'add locations and size to myrec4
    myrec4.Top=100
    myrec4.Left=100
    myrec4.Width=10
    myrec4.Height=100
    'then add myrec4 to Shape container
    SC.Shapes.Add(myrec4)
    'add myrec4 to Form1
    Me.Controls.Add(myrec4)
    'do the above for all 7 rectangleshapes

    'For the dictionary,add number 1's rectangleshape (turned on)
    Dim mylist As List(Of String)
    mylist.Add("shp4")
    mylist.Add("shp5")
    dicRSBackColor.Add(1,mylist)
    'add number 2 rectangles (turned on)
    mylist.Clear()
    mylist.Add("shp1")
    mylist.Add("shp3")
    mylist.Add("shp4")
    mylist.Add("shp6")
    mylist.Add("shp7")
    dicRSBackColor.Add(2,mylist)
    'continue until all 7 rec's added

最后,在按钮 _Click for number 1 中,使用以下内容:

'First change background color of all rectangleshapes to Form1's back color
For Each rs As RectangleShape In Me.SC.Shapes
    rs.BackColor = Me.BackColor
Next
'Now pull the list of shapes that are turned on for number 1 using the dictionary
Dim mylist1 As List(Of String)
mylist1 = dicRSBackColor(1) 'you're pulling the value for key=1,which is a list of strings
'use a double loop and find out when the list value is the same as the name of the rectangleshape,and then set the back color to orange
For Each item In mylist1
    For Each rs As RectangleShape In Me.SC.Shapes
        If item = rs.Name Then rs.BackColor = Color.Orange
    Next
Next