Попытка получить СУММУ ListBox выбранных элементов из локального DataTable в метку - PullRequest
0 голосов
/ 28 августа 2018

Я искал несколько дней, чтобы найти любую возможную ссылку или предложение, и все, с чем я столкнулся, не сработало.

Цель:

Пользователь выберет опции в ComboBox1, которые затем определят доступные опции в ComboBox2, а затем заполнит список операций в ListBox1.

Когда пользователь выбирает доступные операции в ListBox1, мне нужно, чтобы вывод был суммой значений (общее время в минутах в данном случае) в метке для отображения.

Данные, используемые в хранятся в локальной БД. Пока что все работает с моими списками и списком.

Я пытаюсь получить значение Text всех выбранных элементов в ListBox1, чтобы вывести числовое значение в моей таблице (столбец 4 «OperationsTime»), в метку, которая будет отображать сумму всех выбранных элементов (Total Time In Протокол).

Некоторые вещи, которые я пробовал из других сообщений:

  1.  Label9.Text = ListBox1.ValueMember
    
  2.  Label9.Text = ListBox1.ValueMember.ToString
    
  3.  Label9.Text = CType(ListBox1.SelectedItem, DataRowView).Row.Item("OperationsTime").ToString
    

Попытка с использованием Double:

         Dim Total As Double = 0
    For Each Time As Integer In ListBox1.SelectedItems
        Total += CDbl(Time.ToString.Substring(Time.ToString.LastIndexOf(",") + 1))
    Next
    Label9.Text = Total.ToString

Снимок экрана таблицы: Таблица данных операций

Ниже мой код:

Imports System.Data
Imports System.Configuration
Imports System.Data.SqlClient

Public Class MainHome
    Private Function GetData(ByVal sql As String) As DataTable
        Dim constr As String = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\hartj\Documents\visual studio 2015\Projects\TIMEMATRIX2.0\TIMEMATRIX2.0\TMX.mdf;Integrated Security=True"
        Using con As SqlConnection = New SqlConnection(constr)
            Using sda As SqlDataAdapter = New SqlDataAdapter(sql, con)
                Dim dt As DataTable = New DataTable()
                sda.Fill(dt)
                Dim row As DataRow = dt.NewRow()
                row(0) = 1
                row(1) = "Please Select"
                dt.Rows.InsertAt(row, 0)
                Return dt
            End Using
        End Using
    End Function

    Private Sub MainHome_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        ComboBox1.DataSource = Me.GetData("SELECT  SizeId, SizeName FROM Size")
        ComboBox1.DisplayMember = "SizeName"
        ComboBox1.ValueMember = "SizeId"
        ComboBox2.Enabled = False
        ComboBox3.Enabled = False
    End Sub

    Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
        ComboBox2.DataSource = Nothing
        ComboBox3.DataSource = Nothing
        ComboBox2.Enabled = False
        ComboBox3.Enabled = False
        If ComboBox1.SelectedValue.ToString() <> "0" Then
            Dim sql As String = String.Format("SELECT DetailLevelId, DetailLevelName FROM DetailLevel WHERE SizeId = {0}", ComboBox1.SelectedValue)
            ComboBox2.DataSource = Me.GetData(sql)
            ComboBox2.DisplayMember = "DetailLevelName"
            ComboBox2.ValueMember = "DetailLevelId"
            ComboBox2.Enabled = True
        End If
    End Sub

    Private Sub ComboBox2_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox2.SelectionChangeCommitted
        ListBox1.DataSource = Nothing
        ListBox1.Enabled = False
        If ComboBox2.SelectedValue.ToString() <> "0" Then
            Dim sql As String = String.Format("SELECT OperationsId, OperationsName, OperationsTime FROM Operations WHERE DetailLevelId = {0}", ComboBox2.SelectedValue)
            ListBox1.DataSource = Me.GetData(sql)
            ListBox1.ValueMember = "OperationsName"
            ListBox1.ValueMember = "OperationsTime"
            ListBox1.Enabled = True

            Label9.Text = CType(ListBox1.SelectedValue, Integer).ToString
            'Label.Text = CType(cbbank.SelectedItem, DataRowView).Row.Item("Account").ToString
        End IF
    End Sub

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Я сделал несколько изменений в вашем коде. Это работает с ListBox. Подробности смотрите в комментариях.

' "Please Select" doesn't work well in the ListBox, I added it as an option
Private Shared Function GetData(ByVal sql As String, insertPleaseSelect As Boolean) As DataTable
    Dim constr As String = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\hartj\Documents\visual studio 2015\Projects\TIMEMATRIX2.0\TIMEMATRIX2.0\TMX.mdf;Integrated Security=True"
    Using con As SqlConnection = New SqlConnection(constr)
        Using sda As SqlDataAdapter = New SqlDataAdapter(sql, con)
            Dim dt As DataTable = New DataTable()
            sda.Fill(dt)
            If insertPleaseSelect Then
                Dim row As DataRow = dt.NewRow()
                row(0) = 1
                row(1) = "Please Select"
                dt.Rows.InsertAt(row, 0)
            End If
            Return dt
        End Using
    End Using
End Function

Private Sub MainHome_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    ComboBox1.DataSource = GetData("SELECT  [SizeId], [SizeName] FROM [Size]", True)
    ComboBox1.DisplayMember = "SizeName"
    ComboBox1.ValueMember = "SizeId"
    ComboBox2.Enabled = False
    ListBox1.SelectionMode = SelectionMode.MultiSimple ' allow multi-select
End Sub

Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
    ComboBox2.DataSource = Nothing
    ComboBox2.Enabled = False
    If ComboBox1.SelectedValue.ToString() <> "0" Then
        Dim sql As String = String.Format("SELECT [DetailLevelId], [DetailLevelName] FROM [DetailLevel] WHERE [SizeId] = {0}", ComboBox1.SelectedValue)
        ComboBox2.DataSource = GetData(sql, True)
        ComboBox2.DisplayMember = "DetailLevelName"
        ComboBox2.ValueMember = "DetailLevelId"
        ComboBox2.Enabled = True
    End If
End Sub

Private Sub ComboBox2_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox2.SelectionChangeCommitted
    ListBox1.DataSource = Nothing
    ListBox1.Enabled = False
    If ComboBox2.SelectedValue.ToString() <> "0" Then
        Dim sql As String = String.Format("SELECT [OperationsId], [OperationsName], [OperationsTime] FROM [Operations] WHERE [DetailLevelId] = {0}", ComboBox2.SelectedValue)
        ListBox1.DataSource = GetData(sql, False)
        ListBox1.DisplayMember = "OperationsName" ' changed this from ValueMember to DisplayMember
        ListBox1.ValueMember = "OperationsTime"
        ListBox1.Enabled = True
        ListBox1.ClearSelected() ' Every time the ListBox is populated, clear it
    End If
End Sub

' Added this handler to respond to user input, not programmatic selection changes
Private Sub ListBox1_Click(sender As Object, e As EventArgs) Handles ListBox1.Click
    ' Here is the sum
    Label9.Text = ListBox1.SelectedItems.OfType(Of DataRowView).Sum(Function(o) CType(o("OperationsTime"), Double))
End Sub
0 голосов
/ 29 августа 2018
Dim totalOperationsTime As Double

For Each view As DataRowView In ListBox1.SelectedItems
    totalOperationsTime += CDbl(view("OperationsTime"))
Next

Нет необходимости получать DataRow от DataRowView, потому что вы можете получить доступ к значениям поля непосредственно из DataRowView. Он может и делает то же самое, что делает DataRow.

Это самый обычный способ, но есть и другие варианты. Вы могли бы бросить немного LINQ на это:

Dim totalOperationsTime = ListBox1.SelectedItems.Cast(Of DataRowView)().
                                                 Sum(Function(view) CDbl(view("OperationsTime")))

Несколько раздражает, что свойство ValueMember только помогает вам получить значение для SelectedItem. Вот класс, который я написал некоторое время назад и который добавляет метод GetItemValue, который использует ValueMember так же, как метод GetItemText для DisplayMember:

Public Class ListBoxEx
    Inherits ListBox

    Public Function GetItemValue(item As Object) As Object
        Dim index = Me.Items.IndexOf(item)

        If (index <> -1 AndAlso Me.DataManager IsNot Nothing) Then
            Return Me.FilterItemOnProperty(Me.DataManager.List(index), Me.ValueMember)
        End If

        Return Nothing
    End Function

End Class

Если вы используете этот элемент управления вместо обычного ListBox, тогда вы можете сделать это:

Dim totalOperationsTime As Double

For Each item In ListBoxEx1.SelectedItems
    totalOperationsTime += CDbl(ListBoxEx1.GetItemValue(item))
Next

или это:

Dim totalOperationsTime = ListBox1.SelectedItems.Cast(Of Object)().
                                                 Sum(Function(item) CDbl(ListBoxEx1.GetItemValue(item)))

Одним из преимуществ использования этого пользовательского элемента управления является то, что вам не нужно знать, к какому типу относится источник данных или его элементы. Вам нужно только знать, что ValueMember установлено.

...