在另一个combobox值更改后更改combobox的数据源

piah890a  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(368)

我对在visualstudio(最近从msaccess转换过来)中开发应用程序还是相当陌生的,我正在vb.net中编写代码。我的问题是关于如何根据对另一个组合框的选择来更改第二个组合框。我的所有结果都存储在单独的sql server数据库中。
当我的表格被调用时,以下将执行;

Public Sub New(ByVal _PartID As String)

    InitializeComponent() 'Required at the begining of calling a new form'

    LoadCombobox(cboArea, "SELECT [ID], [Name], [MRPShow] FROM [LocationArea] WHERE [MRPShow] = 1", "Name", "ID")

    cboArea.SelectedValue = 0
    cboBay.SelectedValue = 0

    LoadPartData(_PartID)

End Sub

Public Sub LoadCombobox(_cbo As ComboBox, _query As String, _displayMember As String, _valueMember As String)

    Dim SQL As New SQLControl

    _cbo.Items.Clear()

    SQL.ExecQuery(_query)

    If SQL.HasException(True) Then Exit Sub

    _cbo.DataSource = SQL.DBDT

    _cbo.DisplayMember = _displayMember
    _cbo.ValueMember = _valueMember

End Sub

Public Sub LoadPartData(_ID As String)

    Sql.AddParam("@ID", _ID)
    Sql.ExecQuery("SELECT * FROM [Part] " &
                      "WHERE ID = @ID")

    If Sql.RecordCount < 1 Then
        MsgBox("No item found.")
        Exit Sub
    End If

    For Each r As DataRow In Sql.DBDT.Rows

        txtID.Text = r("ID").ToString()
        txtMRPID.Text = r("MRP_ID").ToString()
        txtPartName.Text = r("PartName").ToString()
        txtManufacturer.Text = r("Manufacturer").ToString()
        txtManufacturerPartNo.Text = r("PartNumber").ToString()

        cboVendor1.SelectedValue = r("Vendor1")
        txtWebsiteVendor1.Text = r("Vendor1Link").ToString()
        cboVendor2.SelectedValue = r("Vendor2")
        txtWebsiteVendor2.Text = r("Vendor2Link").ToString()
        cboVendor3.SelectedValue = r("Vendor3")
        txtWebsiteVendor3.Text = r("Vendor3Link").ToString()

        cboArea.SelectedValue = r("LocationArea")
        cboBay.SelectedValue = r("LocationBay")
        cboRack.SelectedValue = r("LocationRack")

        cboPartAssembly.SelectedValue = r("PartAssembly")
        txtDrawingNo.Text = r("DrawingNumber").ToString()
        txtImagePath.Text = r("Image").ToString()

    Next

    If Not String.IsNullOrEmpty(txtWebsiteVendor3.Text) Then

        Process.Start(txtWebsiteVendor3.Text)

    End If

End Sub

我的sqlcontrol类的代码段

Imports System.Data.SqlClient

Public Class SQLControl
    Private DBCon As New SqlConnection("---HIDDEN---")
    Private DBCmd As SqlCommand

    ' DB DATA
    Public DBDA As SqlDataAdapter
    Public DBDT As DataTable

    ' QUERY PARAMETERS
    Public Params As New List(Of SqlParameter)

    ' QUERY STATISTICS
    Public RecordCount As Integer
    Public Exception As String

    Public Sub New()
    End Sub

    ' ALLOW CONNECTION STRING OVERRIDE
    Public Sub New(ConnectionString As String)
        DBCon = New SqlConnection(ConnectionString)
    End Sub

    ' EXECUTE QUERY SUB
    Public Sub ExecQuery(Query As String, Optional ReturnID As Boolean = False)
        ' RESET QUERY STATS
        RecordCount = 0
        Exception = ""

        Try
            DBCon.Open()

            ' CREATE DB COMMAND
            DBCmd = New SqlCommand(Query, DBCon)

            ' LOAD PARAMS INTO DB COMMAND
            Params.ForEach(Sub(p) DBCmd.Parameters.Add(p))

            ' CLEAR PARAM LIST
            Params.Clear()

            ' EXECUTE COMMAND & FILL DATASET
            DBDT = New DataTable
            DBDA = New SqlDataAdapter(DBCmd)
            RecordCount = DBDA.Fill(DBDT)

            If ReturnID = True Then

                Dim ReturnQuery As String = "SELECT @@IDENTITY As LastID;"
                DBCmd = New SqlCommand(ReturnQuery, DBCon)
                DBDT = New DataTable
                DBDA = New SqlDataAdapter(DBCmd)
                RecordCount = DBDA.Fill(DBDT)

            End If

        Catch ex As Exception
            ' CAPTURE ERROR
            Exception = "ExecQuery Error: " & vbNewLine & ex.Message
        Finally
            ' CLOSE CONNECTION
            If DBCon.State = ConnectionState.Open Then DBCon.Close()
        End Try
    End Sub

    ' ADD PARAMETERS
    Public Sub AddParam(Name As String, Value As Object)
        Dim NewParam As New SqlParameter(Name, Value)
        Params.Add(NewParam)
    End Sub

    ' ERROR CHECKING
    Public Function HasException(Optional Report As Boolean = False) As Boolean
        If String.IsNullOrEmpty(Exception) Then Return False
        If Report = True Then MsgBox(Exception, MsgBoxStyle.Critical, "Exception:")
        Return True
    End Function
End Class

因此,我希望实现的是当[cboarea]值更改时,下一个组合框[cbobay]将更新为以下内容:;

Private Sub cboArea_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboArea.SelectedIndexChanged

    cboBay.SelectedValue = 0

    Try

        SQL.AddParam("@SelectedValueOfcboArea", cboArea.SelectedValue)
        SQL.ExecQuery("SELECT [ID], [Name], [LocationAreaID] FROM [LocationBay] WHERE [LocationAreaID] = @SelectedValueOfcboArea")

        If SQL.HasException(True) Then Exit Sub

        cboBay.DataSource = SQL.DBDT

        cboBay.DisplayMember = "Name"
        cboBay.ValueMember = "ID"

    Catch ex As Exception

    End Try

End Sub

上面的内容似乎工作正常,但是当我第一次打开带有特定partid的表单时,我收到以下错误消息;


我相信这些都是初始化代码的错误,在初始化代码中,部件数据被加载到每个控件中,因此调用onvaluechanged事件,该事件不断抛出异常错误,但是我正在努力确定如何解决这个问题,因为我说的是,在加载表单和用户执行操作之后,代码工作正常。
关于另一个问题,我在这里所做的关于从sql数据库收集数据的工作是最好的方法吗?我知道大多数人都遵循这个原则,但我也一直在研究数据集并将其绑定到控件,但我没有看到一篇文章说明什么样的实现方式更好/更快?

mlnl4t2r

mlnl4t2r1#

将用户界面代码与数据库代码分开是一种很好的做法。你的分离是非常好的,除了几个消息框,你从你的家庭显示 SqlControl . 此功能不应与数据库代码混合使用。假设ui更改为web应用程序。反之亦然。ui不应该关心数据来自何处。它可能是火星上一个网络服务的本地计算机上的一个文本文件。
我已经在 SQLContol shared,这意味着调用代码不需要创建 SQLControl . 类与所有示例“共享”相同的数据。类唯一的数据是 ConStr 所以这很好。
连接和命令应该在使用它们的方法的本地。使用…end using块确保即使有错误也关闭并释放它们。dispose对于允许连接返回到连接池并释放非托管资源非常重要。
参数应包括 SqlDbType 以及 Size 如适用。请参阅以下文章了解原因。http://www.dbdelta.com/addwithvalue-is-evil/ 以及https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/ 还有一个:https://dba.stackexchange.com/questions/195937/addwithvalue-performance-and-plan-cache-implications 这是另一个https://andrevdm.blogspot.com/2010/12/parameterised-queriesdont-use.html
通常id是整数。我就是这样设置代码的。如果它们确实是弦的话,你就必须改变它们。
你可能已经试着太过普通太快了。一旦您熟悉了sql server和vb.net,您可能需要重新组合一些代码以避免重复。
您没有显示 @@Identity . ScopeIdentity 它的回报有点限制,所以你有更好的机会得到你期望的价值。与access不同,sqlserver可以在一条语句中执行多个命令。我添加了一个函数来演示。
很抱歉,这些都没有经过测试,但我也做过很多次类似的测试。

Public Class Form2
    PartID As Integer
    Public Sub New(ByVal _PartID As Integer)
        InitializeComponent() 'Required at the begining of calling a new form'            
    End Sub

    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Try
            cboArea.DataSource = SQLControl.GetAreaData
            cboArea.DisplayMember = "Name"
            cboArea.ValueMember = "ID"
        Catch ex As Exception
            MessageBox.Show($"Error filling Area drop down list. {vbCrLf}{ex.Message}")
        End Try
        LoadPartData(PartID)
    End Sub

    Public Sub LoadPartData(_ID As Integer)
        Dim dt As DataTable
        Try
            dt = SQLControl.GetPartByID(_ID)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            Exit Sub
        End Try
        txtID.Text = dt(0)("ID").ToString()
        txtMRPID.Text = dt(0)("MRP_ID").ToString()
        txtPartName.Text = dt(0)("PartName").ToString()
        txtManufacturer.Text = dt(0)("Manufacturer").ToString()
        txtManufacturerPartNo.Text = dt(0)("PartNumber").ToString()
        cboVendor1.SelectedValue = dt(0)("Vendor1")
        txtWebsiteVendor1.Text = dt(0)("Vendor1Link").ToString()
        cboVendor2.SelectedValue = dt(0)("Vendor2")
        txtWebsiteVendor2.Text = dt(0)("Vendor2Link").ToString()
        cboVendor3.SelectedValue = dt(0)("Vendor3")
        txtWebsiteVendor3.Text = dt(0)("Vendor3Link").ToString()
        cboArea.SelectedValue = dt(0)("LocationArea")
        cboBay.SelectedValue = dt(0)("LocationBay")
        cboRack.SelectedValue = dt(0)("LocationRack")
        cboPartAssembly.SelectedValue = dt(0)("PartAssembly")
        txtDrawingNo.Text = dt(0)("DrawingNumber").ToString()
        txtImagePath.Text = dt(0)("Image").ToString()
        If Not String.IsNullOrEmpty(txtWebsiteVendor3.Text) Then
            Process.Start(txtWebsiteVendor3.Text)
        End If
    End Sub

    Private Sub cboArea_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboArea.SelectedIndexChanged
        Dim dt As DataTable
        Try
            dt = SQLControl.GetBayDataByArea(CInt(cboArea.SelectedValue))
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            Exit Sub
        End Try
        cboBay.DataSource = dt
        cboBay.DisplayMember = "Name"
        cboBay.ValueMember = "ID"
    End Sub

End Class

Public Class SQLControl

    Private Shared ConStr As String = "Your connection string" 'Set from a secure location

    Public Shared Function GetPartByID(PartID As Integer) As DataTable
        Dim dt As New DataTable
        Using cn As New SqlConnection(ConStr),
                cmd As New SqlCommand("SELECT * FROM [Part] WHERE ID = @ID", cn)
            cmd.Parameters.Add("@ID", SqlDbType.Int).Value = PartID
            cn.Open()
            dt.Load(cmd.ExecuteReader)
        End Using
        Return dt
    End Function

    Public Shared Function GetAreaData() As DataTable
        Dim dt As New DataTable
        Using cn As New SqlConnection(ConStr),
                cmd As New SqlCommand("SELECT [ID], [Name], [MRPShow] FROM [LocationArea] WHERE [MRPShow] = 1", cn)
            cn.Open()
            dt.Load(cmd.ExecuteReader)
        End Using
        Return dt
    End Function

    Public Shared Function GetBayDataByArea(AreaID As Integer) As DataTable
        Dim dt As New DataTable
        Using cn As New SqlConnection(ConStr),
                cmd As New SqlCommand("SELECT [ID], [Name], [LocationAreaID] FROM [LocationBay] WHERE [LocationAreaID] = @AreaID", cn)
            cmd.Parameters.Add("@AreaID", SqlDbType.Int).Value = AreaID
            cn.Open()
            dt.Load(cmd.ExecuteReader)
        End Using
        Return dt
    End Function

    Public Shared Function InsertData(Name As String, SomeInfo As String) As Integer
        Dim id As Integer
        Using cn As New SqlConnection(ConStr),
                cmd As New SqlCommand("Inset Into SomeTable (Name, SomeInfo) Values (@Name, @SomeInfo); Select SCOPE_IDENTITY;", cn)
            cmd.Parameters.Add("@Name", SqlDbType.NVarChar, 100).Value = Name
            cmd.Parameters.Add("@SomeInfo", SqlDbType.NVarChar, 300).Value = SomeInfo
            cn.Open()
            id = CInt(cmd.ExecuteScalar)
        End Using
        Return id
    End Function

End Class

相关问题