Текстовое поле учитывает только одну переменную вместо суммирования обеих

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

Изображение

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

(Это для определения цены на основе использования)

Налог на услуги составляет 6%, я уже указал его в переменной налога на услуги.

    Select Case True
        Case mar >= 1 To mar <= 200
            unitsConsumedMar = mar
            marTotalAmount = (unitsConsumedMar * 0.109)
            serviceTax = marTotalAmount * serviceTax
            marTotalAmount += serviceTax
            TextBox16.Text = marTotalAmount.ToString("C2")


        Case apr >= 1 To apr <= 200
            unitsConsumedApr = apr
            aprTotalAmount = (unitsConsumedApr * 0.109)
            serviceTax = aprTotalAmount * serviceTax
            aprTotalAmount += serviceTax
            TextBox16.Text = aprTotalAmount.ToString("C2")
        End Select

    Select Case True

        Case mar > "200" And mar <= "300"
            unitsConsumedMar = mar
            marTotalAmount = (unitsConsumedMar * 0.153)
            serviceTax = marTotalAmount * serviceTax
            marTotalAmount += serviceTax
            TextBox16.Text = marTotalAmount.ToString("C2")


        Case apr > "200" And apr <= "300"
            unitsConsumedApr = apr
            aprTotalAmount = (unitsConsumedApr * 0.153)
            serviceTax = aprTotalAmount * serviceTax
            aprTotalAmount += serviceTax
            TextBox16.Text = aprTotalAmount.ToString("C2")
        End Select

      totalBill = Val(marTotalAmount) + Val(aprTotalAmount)
      textbox20.Text = totalBill.ToString("C2")

Все это работает, если март — 200, а апрель — 201, но затем textbox16 возвращает какую-то странную сумму, похоже, что она суммирует сумму как за март, так и за апрель, а не добавляет ее к textbox20.

Изображение

по какой-то причине, если я помещаю 200 в одно текстовое поле и 201 в другое, он вычисляет правильно, поскольку 70,98 + 23,11 - это 94,09, но общая сумма за месяц не должна быть 70,98, поскольку 23,11 + 32,60 даже близко не 70...


person CoreVisional    schedule 25.09.2020    source источник
comment
Вам нужно отладить свой код, т.е. установить точку останова вверху, а затем пройтись по коду строка за строкой, проверяя состояние на каждом шаге. Вы знаете, что вы ожидаете, перед каждым шагом, и вы можете сравнить это с тем, что на самом деле происходит после. Как только они не совпадают, вы нашли свою проблему и можете исследовать ее конкретно, вместо того, чтобы соглашаться на по какой-то причине. Даже если вы все еще не можете решить проблему, по крайней мере, вы можете предоставить нам всю необходимую информацию.   -  person jmcilhinney    schedule 25.09.2020
comment
Вы имеете в виду, что первые 200 единиц будут оплачиваться по цене 0,109 доллара США, а все, что превышает 200 единиц, будет оплачиваться по цене 0,153 доллара США? Или все использование оплачивается по более высокому тарифу, если оно превышает 200 единиц?   -  person Mary    schedule 26.09.2020
comment
верный. но 1 единица = 0,109, а если больше 200, то 1 единица = 0,153   -  person CoreVisional    schedule 26.09.2020


Ответы (2)


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

Function GetMonthlyAmount(energyUsage As Double) As Double
    Dim discount As Double = 0.0
    Dim serviceTax As Double = 0.06
    Dim total As Double = 0.0
    
    Select Case energyUsage
        Case 1.0 To 200.00
            discount = 0.109
        Case 200.01 To 300.0
            discount = 0.153
        Case > 300.00
            discount = 0.169
        Case Else
            discount = 0.0100
    End Select
    
    total = energyUsage * discount
    total += (total * serviceTax)
    
    Return total
End Function

Но выше функция возвращает только месячную сумму. Насколько я вижу, вы хотите получить (и отобразить) другие значения, такие как: скидка, налог на услуги и т. д. Итак, я бы предложил создать собственный класс:

Public Class BillOfEnergyUsage
    Private st As Double = 0.06
    Private eu As Double = 0.0
    Private di AS Double = 0.0
    Private dia AS Double = 0.0
    Private ta As Double = 0.0
    
    Public Sub New(energyUsage As Double)
        eu = energyUsage
        di = Discount
        dia = DiscountAmount
        ta = TotalAmount
    End Sub
    
    Public ReadOnly Property ServiceTax As Double
        Get 
            Return st
        End Get
    End Property
    
    Public Property EnergyUsage As Double
        Get 
            Return eu
        End Get
        Set (value As Double)
            eu = value
        End Set
    End Property
    
    Public ReadOnly Property Discount As Double
        Get 
            Select Case eu
                Case 1.0 To 200.00
                    di = 0.109
                Case 200.01 To 300.0
                    di = 0.153
                Case > 300.00
                    di = 0.169
                Case Else
                    di = 0.0
            End Select
            Return di
        End Get
    End Property

    Public ReadOnly Property DiscountAmount As Double
        Get 
            dia = eu * di
            Return dia
        End Get
    End Property

    Public ReadOnly Property TotalAmount As Double
        Get 
            ta = dia
            ta += (ta * st)
            Return ta
        End Get
    End Property
    
    Public Overrides Function ToString() AS String
        Return $"Usage: {eu.ToString("C2")}, Service Tax: {st.ToString("P2")}, Discount: {di.ToString("P2")} - {dia.ToString("C2")}, Total: {ta.ToString("C2")}"
    End Function
    
End Class

Использование:

Sub Main
    Dim usages As Double() = {120.00, 200.00, 252.00, 300.00, 305.00} 'you have to init your data from textboxes
    Dim beulist As List(Of BillOfEnergyUsage) = New List(Of BillOfEnergyUsage)
    
    For Each usage As Double In usages
        Dim beu As BillOfEnergyUsage = New BillOfEnergyUsage(usage)
        beulist.Add(beu)
        Console.WriteLine(beu.ToString())
    Next
    
    Dim totalAmount = beulist.Sum(Function(x) x.TotalAmount)
    Console.WriteLine($"Total amount: {totalAmount.ToString("C2")}")
End Sub

Результат:

Usage: RM120.00, Service Tax: 6.00%, Discount: 10.90% - RM13.08, Total: RM13.86
Usage: RM200.00, Service Tax: 6.00%, Discount: 10.90% - RM21.80, Total: RM23.11
Usage: RM252.00, Service Tax: 6.00%, Discount: 15.30% - RM38.56, Total: RM40.87
Usage: RM300.00, Service Tax: 6.00%, Discount: 15.30% - RM45.90, Total: RM48.65
Usage: RM305.00, Service Tax: 6.00%, Discount: 16.90% - RM51.55, Total: RM54.64
Total amount: RM181.13

Обратите внимание, что вы можете получить любой счет из списка и получить доступ к его свойствам следующим образом:

Dim bb As BillOfEnergyUsage = beulist(0) 'get first bill from list
Console.WriteLine("{0} | {1} | {2} | {3}", bb.EnergyUsage, bb.ServiceTax, bb.Discount, bb.TotalAmount)

Удачи!

person Maciej Los    schedule 25.09.2020
comment
Проблема в том, что я считаю ежемесячно и с помощью кнопки. У меня есть только одно текстовое поле для хранения значения текущей переменной, которая является месячной суммой. Предположим, что март — это textbox5, а апрель — это textbox6. Если я введу число в textbox5, оно рассчитает все в сумме за месяц, но когда я введу число в апрель, число будет складываться, и если я сделаю одно из них равным ReadOnly = true, тогда как я смогу их суммировать... - person CoreVisional; 25.09.2020
comment
Извините, я вас не понимаю... Количество текстовых полей, размещенных в форме, и их включенный статус не важны! Я предполагаю, что вы не знаете, как перебрать коллекцию текстовых полей. Я прав? - person Maciej Los; 25.09.2020

Я создал класс для данных, связанных с энергетическим полем. Общие поля содержат значения, используемые во всех экземплярах класса. Эти значения устанавливаются в методе Form.Load путем вызова метода SetRates. Поскольку это метод Shared, вам не нужно создавать экземпляр класса. MonthNumber используется для заказа списка счетов за электроэнергию. Возможно, вам придется изменить метод CalculateGrossMonthlyBill, потому что я предположил градуированную скорость. Метод ToString используется полем со списком для определения отображения.

В дизайне формы я назвал каждое текстовое поле в групповом поле MonthlyEnergyUse месяцем, который они представляют. Вы, вероятно, захотите начать со свойства .Text, равного 0. Свойство .Tag каждого месяца — это число, представляющее месяц. 3 марта, 4 апреля и т. д. Эти номера будут использоваться для заказа списка.

В Form.Load установлены тарифы Shared. Хотя я жестко запрограммировал значения, их можно было получить из текстового файла или базы данных. Если их нужно изменить, вам не придется перекомпилировать программу.

После того, как текстовые поля месяца заполнены, нажимается Button1. Сначала пользовательский ввод проверяется с помощью функции .TryParse. Мы создаем список EnergyBill, затем перебираем каждое текстовое поле, вызывая конструктор EnergyBill, передавая значения из свойств текстового поля. Конструктор устанавливает Read Only свойства класса. Этот новый EnergyBill затем добавляется в список.

Далее список упорядочен по MonthNumber с небольшим количеством магии Linq. Затем он привязывается к ComboBox (это заменяет текстовое поле, которое вы пометили как «Месяц» в правой части формы.

Общий итог рассчитывается с использованием .Sum метода списка и отображается в текстовом поле.

Вы можете увидеть данные за каждый месяц, выбрав месяц в поле со списком. Элементы ComboBox являются объектами, но базовым типом является EnergyBill, поэтому мы можем привести элемент и получить доступ ко всем свойствам.

Public Class EnergyBill
    Private _MonthlyChargeWithTax As Decimal
    Private _DiscountAmount As Decimal
    Private _TotalAmount As Decimal
    Private Shared LowUsageRate As Decimal
    Private Shared HighUsageRate As Decimal
    Private Shared DiscountRate As Decimal
    Private Shared TaxRate As Decimal
    Public Property Month As String
    Public Property MonthNumber As Integer
    Public Property EnergyUsage As Double
    Public ReadOnly Property MonthChargeWithTax As Decimal
        Get
            Return _MonthlyChargeWithTax
        End Get
    End Property
    Public ReadOnly Property DiscountAmount As Decimal
        Get
            Return _DiscountAmount
        End Get
    End Property
    Public ReadOnly Property TotalAmount As Decimal
        Get
            Return _TotalAmount
        End Get
    End Property

    Public Sub New(BillingMonth As String, MonthNum As Integer, Usage As Integer)
        Month = BillingMonth
        EnergyUsage = Usage
        MonthNumber = MonthNum
        _MonthlyChargeWithTax = CalculateGrossMonthlyBill(Usage)
        _DiscountAmount = _MonthlyChargeWithTax * DiscountRate
        _TotalAmount = _MonthlyChargeWithTax - _DiscountAmount
    End Sub

    Private Function CalculateGrossMonthlyBill(usage As Integer) As Decimal
        Dim MonthCharge As Decimal
        Select Case usage
            Case <= 200
                MonthCharge = usage * LowUsageRate
            Case Else
                MonthCharge = 200 * LowUsageRate
                MonthCharge += (usage - 200) * HighUsageRate
        End Select
        Return MonthCharge * 1.06D
    End Function

    Public Shared Sub SetRates(LowUsage As Decimal, HighUsage As Decimal, Discount As Decimal, Tax As Decimal)
        LowUsageRate = LowUsage
        HighUsageRate = HighUsage
        DiscountRate = Discount
        TaxRate = Tax
    End Sub

    Public Overrides Function ToString() As String
        Return Month
    End Function
End Class

Форма...

Public Class UtilityBills

    Private Sub UtilityBills_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        EnergyBill.SetRates(0.109D, 0.153D, 0.5D, 0.06D)
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If Not ValidateUsage() Then
            MessageBox.Show("All text boxes must have a valid number.")
            Exit Sub
        End If
        Dim lst As New List(Of EnergyBill)
        For Each tb In GroupBox1.Controls.OfType(Of TextBox)
            Dim eb As New EnergyBill(tb.Name, CInt(tb.Tag), CInt(tb.Text))
            lst.Add(eb)
        Next
        Dim orderedList = (lst.OrderBy(Function(eb) eb.MonthNumber)).ToList
        ComboBox1.DataSource = orderedList
        Dim TotalMonths = lst.Sum(Function(eb) eb.TotalAmount)
        TextBox5.Text = TotalMonths.ToString("C2")
    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
        Dim eb = DirectCast(ComboBox1.SelectedItem, EnergyBill)
        TextBox1.Text = eb.MonthChargeWithTax.ToString("C2")
        TextBox2.Text = eb.DiscountAmount.ToString("C2")
        TextBox3.Text = eb.TotalAmount.ToString("C2")
    End Sub

    Private Function ValidateUsage() As Boolean
        Dim usage As Integer
        For Each tb In GroupBox1.Controls.OfType(Of TextBox)
            If Not Integer.TryParse(tb.Text, usage) Then
                Return False
            End If
        Next
        Return True
    End Function
End Class
person Mary    schedule 26.09.2020