Calculate subtotals and totals from a form with many decimal values











up vote
7
down vote

favorite












I've got 17 currency fields on a form and need to do some calculations with their values. I wrote this method some time ago and have come back to try and refactor it to make it more efficient and/or more readable. Could I have some pointers please?



Note: The variables appended with d are the decimals used to hold the field values, their counterparts without the d are the fields themselves. I am aware that variables could do with renaming to make more sense. Hopefully it's fairly clear what this is doing by looking at the comments.



private void getTotals() {

//declarations of decimal variables
decimal curPurc1d; decimal curPurc2d; decimal curPurc3d; decimal curPurc4d; //purItemxCost
decimal curItem1Totd; decimal curItem2Totd; decimal curItem3Totd; decimal curItem4Totd; //curItemxTot
decimal LessItem1Costd; decimal LessItem2Costd; decimal LessItem3Costd; decimal LessItem4Costd; decimal LessItem5Costd; //LessItemxCost
decimal ditem1Cost = 0; decimal ditem2Cost = 0; decimal ditem3Cost = 0; decimal ditem4Cost = 0; //Full cost of items

//Check if we have some valid numbers, stop if we don't
if ( !decimal.TryParse(curPurc1.Value.ToString(), out curPurc1d)
|| !decimal.TryParse(curPurc2.Value.ToString(), out curPurc2d)
|| !decimal.TryParse(curPurc3.Value.ToString(), out curPurc3d)
|| !decimal.TryParse(curPurc4.Value.ToString(), out curPurc4d)
|| !decimal.TryParse(curItem1Tot.Value.ToString(), out curItem1Totd)
|| !decimal.TryParse(curItem2Tot.Value.ToString(), out curItem2Totd)
|| !decimal.TryParse(curItem3Tot.Value.ToString(), out curItem3Totd)
|| !decimal.TryParse(curItem4Tot.Value.ToString(), out curItem4Totd)
|| !decimal.TryParse(LessItem1Cost.Value.ToString(), out LessItem1Costd)
|| !decimal.TryParse(LessItem2Cost.Value.ToString(), out LessItem2Costd)
|| !decimal.TryParse(LessItem3Cost.Value.ToString(), out LessItem3Costd)
|| !decimal.TryParse(LessItem4Cost.Value.ToString(), out LessItem4Costd)
|| !decimal.TryParse(LessItem5Cost.Value.ToString(), out LessItem5Costd)
)
return;

//For each of the 4 'items', try to get the value as a decimal, but only if the related checkbox is checked.
if (Item1RateYN.Checked)
{
decimal.TryParse(curItem1Cost.Value.ToString(), out ditem1Cost);
}
if (Item2RateYN.Checked)
{
decimal.TryParse(curItem2Cost.Value.ToString(), out ditem2Cost);
}
if (Item3RateYN.Checked)
{
decimal.TryParse(curItem3Cost.Value.ToString(), out ditem3Cost);
}
if (Item4RateYN.Checked)
{
decimal.TryParse(curItem4Cost.Value.ToString(), out ditem3Cost);
}

//Add up some values which are always part of the subtotal and then the ditemx ones, which will be 0 or set to a numerical value depending if the checkbox is checked
decimal subtotals = curPurc1d + curPurc2d + curPurc3d + curPurc4d + curItem1Totd + curItem2Totd + curItem3Totd + curItem4Totd
+ ditem1Cost + ditem2Cost + ditem3Cost + ditem4Cost;
subtotal.Value = subtotals;

//Get total minus the cost of the property (curPurc1d)
costPlusSubTotal.Value = subtotals - curPurc1d;

//add up all the "less" items to know how much to reduce by
decimal lessTotals = LessItem1Costd + LessItem2Costd + LessItem3Costd + LessItem4Costd + LessItem5Costd;
totalLess.Value = lessTotals;

//Total Balance due
//subtotal minus the 'less' values total
decimal total = (subtotals - lessTotals);
//set the final figure into the relevant field
balanceDueTot.Value = total;
}









share|improve this question




























    up vote
    7
    down vote

    favorite












    I've got 17 currency fields on a form and need to do some calculations with their values. I wrote this method some time ago and have come back to try and refactor it to make it more efficient and/or more readable. Could I have some pointers please?



    Note: The variables appended with d are the decimals used to hold the field values, their counterparts without the d are the fields themselves. I am aware that variables could do with renaming to make more sense. Hopefully it's fairly clear what this is doing by looking at the comments.



    private void getTotals() {

    //declarations of decimal variables
    decimal curPurc1d; decimal curPurc2d; decimal curPurc3d; decimal curPurc4d; //purItemxCost
    decimal curItem1Totd; decimal curItem2Totd; decimal curItem3Totd; decimal curItem4Totd; //curItemxTot
    decimal LessItem1Costd; decimal LessItem2Costd; decimal LessItem3Costd; decimal LessItem4Costd; decimal LessItem5Costd; //LessItemxCost
    decimal ditem1Cost = 0; decimal ditem2Cost = 0; decimal ditem3Cost = 0; decimal ditem4Cost = 0; //Full cost of items

    //Check if we have some valid numbers, stop if we don't
    if ( !decimal.TryParse(curPurc1.Value.ToString(), out curPurc1d)
    || !decimal.TryParse(curPurc2.Value.ToString(), out curPurc2d)
    || !decimal.TryParse(curPurc3.Value.ToString(), out curPurc3d)
    || !decimal.TryParse(curPurc4.Value.ToString(), out curPurc4d)
    || !decimal.TryParse(curItem1Tot.Value.ToString(), out curItem1Totd)
    || !decimal.TryParse(curItem2Tot.Value.ToString(), out curItem2Totd)
    || !decimal.TryParse(curItem3Tot.Value.ToString(), out curItem3Totd)
    || !decimal.TryParse(curItem4Tot.Value.ToString(), out curItem4Totd)
    || !decimal.TryParse(LessItem1Cost.Value.ToString(), out LessItem1Costd)
    || !decimal.TryParse(LessItem2Cost.Value.ToString(), out LessItem2Costd)
    || !decimal.TryParse(LessItem3Cost.Value.ToString(), out LessItem3Costd)
    || !decimal.TryParse(LessItem4Cost.Value.ToString(), out LessItem4Costd)
    || !decimal.TryParse(LessItem5Cost.Value.ToString(), out LessItem5Costd)
    )
    return;

    //For each of the 4 'items', try to get the value as a decimal, but only if the related checkbox is checked.
    if (Item1RateYN.Checked)
    {
    decimal.TryParse(curItem1Cost.Value.ToString(), out ditem1Cost);
    }
    if (Item2RateYN.Checked)
    {
    decimal.TryParse(curItem2Cost.Value.ToString(), out ditem2Cost);
    }
    if (Item3RateYN.Checked)
    {
    decimal.TryParse(curItem3Cost.Value.ToString(), out ditem3Cost);
    }
    if (Item4RateYN.Checked)
    {
    decimal.TryParse(curItem4Cost.Value.ToString(), out ditem3Cost);
    }

    //Add up some values which are always part of the subtotal and then the ditemx ones, which will be 0 or set to a numerical value depending if the checkbox is checked
    decimal subtotals = curPurc1d + curPurc2d + curPurc3d + curPurc4d + curItem1Totd + curItem2Totd + curItem3Totd + curItem4Totd
    + ditem1Cost + ditem2Cost + ditem3Cost + ditem4Cost;
    subtotal.Value = subtotals;

    //Get total minus the cost of the property (curPurc1d)
    costPlusSubTotal.Value = subtotals - curPurc1d;

    //add up all the "less" items to know how much to reduce by
    decimal lessTotals = LessItem1Costd + LessItem2Costd + LessItem3Costd + LessItem4Costd + LessItem5Costd;
    totalLess.Value = lessTotals;

    //Total Balance due
    //subtotal minus the 'less' values total
    decimal total = (subtotals - lessTotals);
    //set the final figure into the relevant field
    balanceDueTot.Value = total;
    }









    share|improve this question


























      up vote
      7
      down vote

      favorite









      up vote
      7
      down vote

      favorite











      I've got 17 currency fields on a form and need to do some calculations with their values. I wrote this method some time ago and have come back to try and refactor it to make it more efficient and/or more readable. Could I have some pointers please?



      Note: The variables appended with d are the decimals used to hold the field values, their counterparts without the d are the fields themselves. I am aware that variables could do with renaming to make more sense. Hopefully it's fairly clear what this is doing by looking at the comments.



      private void getTotals() {

      //declarations of decimal variables
      decimal curPurc1d; decimal curPurc2d; decimal curPurc3d; decimal curPurc4d; //purItemxCost
      decimal curItem1Totd; decimal curItem2Totd; decimal curItem3Totd; decimal curItem4Totd; //curItemxTot
      decimal LessItem1Costd; decimal LessItem2Costd; decimal LessItem3Costd; decimal LessItem4Costd; decimal LessItem5Costd; //LessItemxCost
      decimal ditem1Cost = 0; decimal ditem2Cost = 0; decimal ditem3Cost = 0; decimal ditem4Cost = 0; //Full cost of items

      //Check if we have some valid numbers, stop if we don't
      if ( !decimal.TryParse(curPurc1.Value.ToString(), out curPurc1d)
      || !decimal.TryParse(curPurc2.Value.ToString(), out curPurc2d)
      || !decimal.TryParse(curPurc3.Value.ToString(), out curPurc3d)
      || !decimal.TryParse(curPurc4.Value.ToString(), out curPurc4d)
      || !decimal.TryParse(curItem1Tot.Value.ToString(), out curItem1Totd)
      || !decimal.TryParse(curItem2Tot.Value.ToString(), out curItem2Totd)
      || !decimal.TryParse(curItem3Tot.Value.ToString(), out curItem3Totd)
      || !decimal.TryParse(curItem4Tot.Value.ToString(), out curItem4Totd)
      || !decimal.TryParse(LessItem1Cost.Value.ToString(), out LessItem1Costd)
      || !decimal.TryParse(LessItem2Cost.Value.ToString(), out LessItem2Costd)
      || !decimal.TryParse(LessItem3Cost.Value.ToString(), out LessItem3Costd)
      || !decimal.TryParse(LessItem4Cost.Value.ToString(), out LessItem4Costd)
      || !decimal.TryParse(LessItem5Cost.Value.ToString(), out LessItem5Costd)
      )
      return;

      //For each of the 4 'items', try to get the value as a decimal, but only if the related checkbox is checked.
      if (Item1RateYN.Checked)
      {
      decimal.TryParse(curItem1Cost.Value.ToString(), out ditem1Cost);
      }
      if (Item2RateYN.Checked)
      {
      decimal.TryParse(curItem2Cost.Value.ToString(), out ditem2Cost);
      }
      if (Item3RateYN.Checked)
      {
      decimal.TryParse(curItem3Cost.Value.ToString(), out ditem3Cost);
      }
      if (Item4RateYN.Checked)
      {
      decimal.TryParse(curItem4Cost.Value.ToString(), out ditem3Cost);
      }

      //Add up some values which are always part of the subtotal and then the ditemx ones, which will be 0 or set to a numerical value depending if the checkbox is checked
      decimal subtotals = curPurc1d + curPurc2d + curPurc3d + curPurc4d + curItem1Totd + curItem2Totd + curItem3Totd + curItem4Totd
      + ditem1Cost + ditem2Cost + ditem3Cost + ditem4Cost;
      subtotal.Value = subtotals;

      //Get total minus the cost of the property (curPurc1d)
      costPlusSubTotal.Value = subtotals - curPurc1d;

      //add up all the "less" items to know how much to reduce by
      decimal lessTotals = LessItem1Costd + LessItem2Costd + LessItem3Costd + LessItem4Costd + LessItem5Costd;
      totalLess.Value = lessTotals;

      //Total Balance due
      //subtotal minus the 'less' values total
      decimal total = (subtotals - lessTotals);
      //set the final figure into the relevant field
      balanceDueTot.Value = total;
      }









      share|improve this question















      I've got 17 currency fields on a form and need to do some calculations with their values. I wrote this method some time ago and have come back to try and refactor it to make it more efficient and/or more readable. Could I have some pointers please?



      Note: The variables appended with d are the decimals used to hold the field values, their counterparts without the d are the fields themselves. I am aware that variables could do with renaming to make more sense. Hopefully it's fairly clear what this is doing by looking at the comments.



      private void getTotals() {

      //declarations of decimal variables
      decimal curPurc1d; decimal curPurc2d; decimal curPurc3d; decimal curPurc4d; //purItemxCost
      decimal curItem1Totd; decimal curItem2Totd; decimal curItem3Totd; decimal curItem4Totd; //curItemxTot
      decimal LessItem1Costd; decimal LessItem2Costd; decimal LessItem3Costd; decimal LessItem4Costd; decimal LessItem5Costd; //LessItemxCost
      decimal ditem1Cost = 0; decimal ditem2Cost = 0; decimal ditem3Cost = 0; decimal ditem4Cost = 0; //Full cost of items

      //Check if we have some valid numbers, stop if we don't
      if ( !decimal.TryParse(curPurc1.Value.ToString(), out curPurc1d)
      || !decimal.TryParse(curPurc2.Value.ToString(), out curPurc2d)
      || !decimal.TryParse(curPurc3.Value.ToString(), out curPurc3d)
      || !decimal.TryParse(curPurc4.Value.ToString(), out curPurc4d)
      || !decimal.TryParse(curItem1Tot.Value.ToString(), out curItem1Totd)
      || !decimal.TryParse(curItem2Tot.Value.ToString(), out curItem2Totd)
      || !decimal.TryParse(curItem3Tot.Value.ToString(), out curItem3Totd)
      || !decimal.TryParse(curItem4Tot.Value.ToString(), out curItem4Totd)
      || !decimal.TryParse(LessItem1Cost.Value.ToString(), out LessItem1Costd)
      || !decimal.TryParse(LessItem2Cost.Value.ToString(), out LessItem2Costd)
      || !decimal.TryParse(LessItem3Cost.Value.ToString(), out LessItem3Costd)
      || !decimal.TryParse(LessItem4Cost.Value.ToString(), out LessItem4Costd)
      || !decimal.TryParse(LessItem5Cost.Value.ToString(), out LessItem5Costd)
      )
      return;

      //For each of the 4 'items', try to get the value as a decimal, but only if the related checkbox is checked.
      if (Item1RateYN.Checked)
      {
      decimal.TryParse(curItem1Cost.Value.ToString(), out ditem1Cost);
      }
      if (Item2RateYN.Checked)
      {
      decimal.TryParse(curItem2Cost.Value.ToString(), out ditem2Cost);
      }
      if (Item3RateYN.Checked)
      {
      decimal.TryParse(curItem3Cost.Value.ToString(), out ditem3Cost);
      }
      if (Item4RateYN.Checked)
      {
      decimal.TryParse(curItem4Cost.Value.ToString(), out ditem3Cost);
      }

      //Add up some values which are always part of the subtotal and then the ditemx ones, which will be 0 or set to a numerical value depending if the checkbox is checked
      decimal subtotals = curPurc1d + curPurc2d + curPurc3d + curPurc4d + curItem1Totd + curItem2Totd + curItem3Totd + curItem4Totd
      + ditem1Cost + ditem2Cost + ditem3Cost + ditem4Cost;
      subtotal.Value = subtotals;

      //Get total minus the cost of the property (curPurc1d)
      costPlusSubTotal.Value = subtotals - curPurc1d;

      //add up all the "less" items to know how much to reduce by
      decimal lessTotals = LessItem1Costd + LessItem2Costd + LessItem3Costd + LessItem4Costd + LessItem5Costd;
      totalLess.Value = lessTotals;

      //Total Balance due
      //subtotal minus the 'less' values total
      decimal total = (subtotals - lessTotals);
      //set the final figure into the relevant field
      balanceDueTot.Value = total;
      }






      c# winforms






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 2 hours ago









      200_success

      128k15149412




      128k15149412










      asked 6 hours ago









      Syntax Error

      1485




      1485






















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          7
          down vote













          Two words: loops and arrays.



          There a bunch of variable names that differ only by a number. Whenever you see code like this, you can probably clean it up by creating a collection of those things and looping over them. Basically, you have a checkbox and text field repeated multiple times, and one field where you display the total of all checked fields.




          1. Create a user control to encapsulate the checkbox and text field

          2. Make sure this user control has a public property decimal TotalCost { get } that will:


            • Return the decimal-parsed values of total - cost for the fields when checked, and zero when unchecked.

            • Throws an exception if the decimal cannot be parsed



          3. Expose a boolean property bool IsValid that returns true when the user as entered a valid decimals

          4. Expose a public property bool IsChecked that returns whether or not the checkbox is checked

          5. Create a collection of these user controls, one for each checkbox/text field combo on screen


          Now loop and process:



          decimal purchaseTotal = 0m;
          decimal totalAmount = 0m;

          foreach (var control in PurchasedItems.Where(p => p.IsChecked && p.IsValid))
          {
          purchaseTotal += control.TotalCost;
          }


          I left some details out, but your code isn't really clear on what the UI looks like, or what the business use case is, but it really just boils down to:




          • Create an abstraction for what each combo of controls represents (e.g. create a new user control)

          • Create a collection of these controls

          • Loop and calculate






          share|improve this answer




























            up vote
            4
            down vote













            Assuming the fields have definitions like the following



            public class TextboxControl
            {
            public object Value { get; set; }
            }

            public class CheckboxControl
            {
            public bool Checked { get; set; }
            }


            I would create some extensions for them in order to reduce code duplication and increase readability, and pretty much this is the core idea.



            public static class ControlsExtensions
            {
            public static bool HasValue(this TextboxControl source)
            => decimal.TryParse(source.Value.ToString(), out _);

            public static decimal GetValue(this TextboxControl source)
            => decimal.Parse(source.Value.ToString());

            public static decimal GetOptionalValue(this TextboxControl source, CheckboxControl checkbox)
            {
            if (checkbox.Checked)
            {
            decimal value = decimal.TryParse(source.Value.ToString(), out value) ? value : 0;
            return value;
            }
            return default(decimal);
            }
            }


            Then my next step in refactoring would to use these extensions and rearrange a bit the lines to increase cohesion



            private void getTotals()
            {
            //Check if we have some valid numbers, stop if we don't
            if ( !curPurc1.HasValue()
            || !curPurc2.HasValue()
            || !curPurc3.HasValue()
            || !curPurc4.HasValue()
            || !curItem1Tot.HasValue()
            || !curItem2Tot.HasValue()
            || !curItem3Tot.HasValue()
            || !curItem4Tot.HasValue()
            || !LessItem1Cost.HasValue()
            || !LessItem2Cost.HasValue()
            || !LessItem3Cost.HasValue()
            || !LessItem4Cost.HasValue()
            || !LessItem5Cost.HasValue()
            )
            return;

            //Add up some values which are always part of the subtotal and then the ditemx ones, which will be 0 or set to a numerical value depending if the checkbox is checked
            decimal subtotals = curPurc1.GetValue() + curPurc2.GetValue() + curPurc3.GetValue()
            + curPurc4.GetValue() + curItem1Tot.GetValue() + curItem2Tot.GetValue()
            + curItem3Tot.GetValue() + curItem4Tot.GetValue()
            + Item1RateYN.GetOptionalValue() + Item2RateYN.GetOptionalValue() + Item3RateYN.GetOptionalValue() + Item4RateYN.GetOptionalValue();

            //Get total minus the cost of the property (curPurc1d)
            decimal plusSubTotal = subtotals - curPurc1.GetValue();


            //add up all the "less" items to know how much to reduce by
            decimal lessTotals = LessItem1Cost.GetValue() + LessItem2Cost.GetValue() + LessItem3Cost.GetValue() + LessItem4Cost.GetValue() + LessItem5Cost.GetValue();

            //Total Balance due
            //subtotal minus the 'less' values total
            decimal total = (subtotals - lessTotals);

            //update the relevant UI field
            costPlusSubTotal.Value = plusSubTotal;
            subtotal.Value = subtotals;
            balanceDueTot.Value = total;
            totalLess.Value = lessTotals;
            }


            Then to make the code more C#-like, I would




            • use var instead of decimal


            • rename getTotals to GetTotals


            • use_camelCase for private fileds (so Less becomes _less)

            • reduce redundant parenthesis from (subtotals - lessTotals)

            • use brackets {} for the return statement


            Notice that I also grouped the update of the UI at the end of the method.



            I would have some comments also for the name of the method itself as GetTotals implies that the method returns something, but the return signature is void. One idea is to use something like CalculateTotals.






            share|improve this answer























              Your Answer





              StackExchange.ifUsing("editor", function () {
              return StackExchange.using("mathjaxEditing", function () {
              StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
              StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
              });
              });
              }, "mathjax-editing");

              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "196"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209540%2fcalculate-subtotals-and-totals-from-a-form-with-many-decimal-values%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              7
              down vote













              Two words: loops and arrays.



              There a bunch of variable names that differ only by a number. Whenever you see code like this, you can probably clean it up by creating a collection of those things and looping over them. Basically, you have a checkbox and text field repeated multiple times, and one field where you display the total of all checked fields.




              1. Create a user control to encapsulate the checkbox and text field

              2. Make sure this user control has a public property decimal TotalCost { get } that will:


                • Return the decimal-parsed values of total - cost for the fields when checked, and zero when unchecked.

                • Throws an exception if the decimal cannot be parsed



              3. Expose a boolean property bool IsValid that returns true when the user as entered a valid decimals

              4. Expose a public property bool IsChecked that returns whether or not the checkbox is checked

              5. Create a collection of these user controls, one for each checkbox/text field combo on screen


              Now loop and process:



              decimal purchaseTotal = 0m;
              decimal totalAmount = 0m;

              foreach (var control in PurchasedItems.Where(p => p.IsChecked && p.IsValid))
              {
              purchaseTotal += control.TotalCost;
              }


              I left some details out, but your code isn't really clear on what the UI looks like, or what the business use case is, but it really just boils down to:




              • Create an abstraction for what each combo of controls represents (e.g. create a new user control)

              • Create a collection of these controls

              • Loop and calculate






              share|improve this answer

























                up vote
                7
                down vote













                Two words: loops and arrays.



                There a bunch of variable names that differ only by a number. Whenever you see code like this, you can probably clean it up by creating a collection of those things and looping over them. Basically, you have a checkbox and text field repeated multiple times, and one field where you display the total of all checked fields.




                1. Create a user control to encapsulate the checkbox and text field

                2. Make sure this user control has a public property decimal TotalCost { get } that will:


                  • Return the decimal-parsed values of total - cost for the fields when checked, and zero when unchecked.

                  • Throws an exception if the decimal cannot be parsed



                3. Expose a boolean property bool IsValid that returns true when the user as entered a valid decimals

                4. Expose a public property bool IsChecked that returns whether or not the checkbox is checked

                5. Create a collection of these user controls, one for each checkbox/text field combo on screen


                Now loop and process:



                decimal purchaseTotal = 0m;
                decimal totalAmount = 0m;

                foreach (var control in PurchasedItems.Where(p => p.IsChecked && p.IsValid))
                {
                purchaseTotal += control.TotalCost;
                }


                I left some details out, but your code isn't really clear on what the UI looks like, or what the business use case is, but it really just boils down to:




                • Create an abstraction for what each combo of controls represents (e.g. create a new user control)

                • Create a collection of these controls

                • Loop and calculate






                share|improve this answer























                  up vote
                  7
                  down vote










                  up vote
                  7
                  down vote









                  Two words: loops and arrays.



                  There a bunch of variable names that differ only by a number. Whenever you see code like this, you can probably clean it up by creating a collection of those things and looping over them. Basically, you have a checkbox and text field repeated multiple times, and one field where you display the total of all checked fields.




                  1. Create a user control to encapsulate the checkbox and text field

                  2. Make sure this user control has a public property decimal TotalCost { get } that will:


                    • Return the decimal-parsed values of total - cost for the fields when checked, and zero when unchecked.

                    • Throws an exception if the decimal cannot be parsed



                  3. Expose a boolean property bool IsValid that returns true when the user as entered a valid decimals

                  4. Expose a public property bool IsChecked that returns whether or not the checkbox is checked

                  5. Create a collection of these user controls, one for each checkbox/text field combo on screen


                  Now loop and process:



                  decimal purchaseTotal = 0m;
                  decimal totalAmount = 0m;

                  foreach (var control in PurchasedItems.Where(p => p.IsChecked && p.IsValid))
                  {
                  purchaseTotal += control.TotalCost;
                  }


                  I left some details out, but your code isn't really clear on what the UI looks like, or what the business use case is, but it really just boils down to:




                  • Create an abstraction for what each combo of controls represents (e.g. create a new user control)

                  • Create a collection of these controls

                  • Loop and calculate






                  share|improve this answer












                  Two words: loops and arrays.



                  There a bunch of variable names that differ only by a number. Whenever you see code like this, you can probably clean it up by creating a collection of those things and looping over them. Basically, you have a checkbox and text field repeated multiple times, and one field where you display the total of all checked fields.




                  1. Create a user control to encapsulate the checkbox and text field

                  2. Make sure this user control has a public property decimal TotalCost { get } that will:


                    • Return the decimal-parsed values of total - cost for the fields when checked, and zero when unchecked.

                    • Throws an exception if the decimal cannot be parsed



                  3. Expose a boolean property bool IsValid that returns true when the user as entered a valid decimals

                  4. Expose a public property bool IsChecked that returns whether or not the checkbox is checked

                  5. Create a collection of these user controls, one for each checkbox/text field combo on screen


                  Now loop and process:



                  decimal purchaseTotal = 0m;
                  decimal totalAmount = 0m;

                  foreach (var control in PurchasedItems.Where(p => p.IsChecked && p.IsValid))
                  {
                  purchaseTotal += control.TotalCost;
                  }


                  I left some details out, but your code isn't really clear on what the UI looks like, or what the business use case is, but it really just boils down to:




                  • Create an abstraction for what each combo of controls represents (e.g. create a new user control)

                  • Create a collection of these controls

                  • Loop and calculate







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 5 hours ago









                  Greg Burghardt

                  4,826619




                  4,826619
























                      up vote
                      4
                      down vote













                      Assuming the fields have definitions like the following



                      public class TextboxControl
                      {
                      public object Value { get; set; }
                      }

                      public class CheckboxControl
                      {
                      public bool Checked { get; set; }
                      }


                      I would create some extensions for them in order to reduce code duplication and increase readability, and pretty much this is the core idea.



                      public static class ControlsExtensions
                      {
                      public static bool HasValue(this TextboxControl source)
                      => decimal.TryParse(source.Value.ToString(), out _);

                      public static decimal GetValue(this TextboxControl source)
                      => decimal.Parse(source.Value.ToString());

                      public static decimal GetOptionalValue(this TextboxControl source, CheckboxControl checkbox)
                      {
                      if (checkbox.Checked)
                      {
                      decimal value = decimal.TryParse(source.Value.ToString(), out value) ? value : 0;
                      return value;
                      }
                      return default(decimal);
                      }
                      }


                      Then my next step in refactoring would to use these extensions and rearrange a bit the lines to increase cohesion



                      private void getTotals()
                      {
                      //Check if we have some valid numbers, stop if we don't
                      if ( !curPurc1.HasValue()
                      || !curPurc2.HasValue()
                      || !curPurc3.HasValue()
                      || !curPurc4.HasValue()
                      || !curItem1Tot.HasValue()
                      || !curItem2Tot.HasValue()
                      || !curItem3Tot.HasValue()
                      || !curItem4Tot.HasValue()
                      || !LessItem1Cost.HasValue()
                      || !LessItem2Cost.HasValue()
                      || !LessItem3Cost.HasValue()
                      || !LessItem4Cost.HasValue()
                      || !LessItem5Cost.HasValue()
                      )
                      return;

                      //Add up some values which are always part of the subtotal and then the ditemx ones, which will be 0 or set to a numerical value depending if the checkbox is checked
                      decimal subtotals = curPurc1.GetValue() + curPurc2.GetValue() + curPurc3.GetValue()
                      + curPurc4.GetValue() + curItem1Tot.GetValue() + curItem2Tot.GetValue()
                      + curItem3Tot.GetValue() + curItem4Tot.GetValue()
                      + Item1RateYN.GetOptionalValue() + Item2RateYN.GetOptionalValue() + Item3RateYN.GetOptionalValue() + Item4RateYN.GetOptionalValue();

                      //Get total minus the cost of the property (curPurc1d)
                      decimal plusSubTotal = subtotals - curPurc1.GetValue();


                      //add up all the "less" items to know how much to reduce by
                      decimal lessTotals = LessItem1Cost.GetValue() + LessItem2Cost.GetValue() + LessItem3Cost.GetValue() + LessItem4Cost.GetValue() + LessItem5Cost.GetValue();

                      //Total Balance due
                      //subtotal minus the 'less' values total
                      decimal total = (subtotals - lessTotals);

                      //update the relevant UI field
                      costPlusSubTotal.Value = plusSubTotal;
                      subtotal.Value = subtotals;
                      balanceDueTot.Value = total;
                      totalLess.Value = lessTotals;
                      }


                      Then to make the code more C#-like, I would




                      • use var instead of decimal


                      • rename getTotals to GetTotals


                      • use_camelCase for private fileds (so Less becomes _less)

                      • reduce redundant parenthesis from (subtotals - lessTotals)

                      • use brackets {} for the return statement


                      Notice that I also grouped the update of the UI at the end of the method.



                      I would have some comments also for the name of the method itself as GetTotals implies that the method returns something, but the return signature is void. One idea is to use something like CalculateTotals.






                      share|improve this answer



























                        up vote
                        4
                        down vote













                        Assuming the fields have definitions like the following



                        public class TextboxControl
                        {
                        public object Value { get; set; }
                        }

                        public class CheckboxControl
                        {
                        public bool Checked { get; set; }
                        }


                        I would create some extensions for them in order to reduce code duplication and increase readability, and pretty much this is the core idea.



                        public static class ControlsExtensions
                        {
                        public static bool HasValue(this TextboxControl source)
                        => decimal.TryParse(source.Value.ToString(), out _);

                        public static decimal GetValue(this TextboxControl source)
                        => decimal.Parse(source.Value.ToString());

                        public static decimal GetOptionalValue(this TextboxControl source, CheckboxControl checkbox)
                        {
                        if (checkbox.Checked)
                        {
                        decimal value = decimal.TryParse(source.Value.ToString(), out value) ? value : 0;
                        return value;
                        }
                        return default(decimal);
                        }
                        }


                        Then my next step in refactoring would to use these extensions and rearrange a bit the lines to increase cohesion



                        private void getTotals()
                        {
                        //Check if we have some valid numbers, stop if we don't
                        if ( !curPurc1.HasValue()
                        || !curPurc2.HasValue()
                        || !curPurc3.HasValue()
                        || !curPurc4.HasValue()
                        || !curItem1Tot.HasValue()
                        || !curItem2Tot.HasValue()
                        || !curItem3Tot.HasValue()
                        || !curItem4Tot.HasValue()
                        || !LessItem1Cost.HasValue()
                        || !LessItem2Cost.HasValue()
                        || !LessItem3Cost.HasValue()
                        || !LessItem4Cost.HasValue()
                        || !LessItem5Cost.HasValue()
                        )
                        return;

                        //Add up some values which are always part of the subtotal and then the ditemx ones, which will be 0 or set to a numerical value depending if the checkbox is checked
                        decimal subtotals = curPurc1.GetValue() + curPurc2.GetValue() + curPurc3.GetValue()
                        + curPurc4.GetValue() + curItem1Tot.GetValue() + curItem2Tot.GetValue()
                        + curItem3Tot.GetValue() + curItem4Tot.GetValue()
                        + Item1RateYN.GetOptionalValue() + Item2RateYN.GetOptionalValue() + Item3RateYN.GetOptionalValue() + Item4RateYN.GetOptionalValue();

                        //Get total minus the cost of the property (curPurc1d)
                        decimal plusSubTotal = subtotals - curPurc1.GetValue();


                        //add up all the "less" items to know how much to reduce by
                        decimal lessTotals = LessItem1Cost.GetValue() + LessItem2Cost.GetValue() + LessItem3Cost.GetValue() + LessItem4Cost.GetValue() + LessItem5Cost.GetValue();

                        //Total Balance due
                        //subtotal minus the 'less' values total
                        decimal total = (subtotals - lessTotals);

                        //update the relevant UI field
                        costPlusSubTotal.Value = plusSubTotal;
                        subtotal.Value = subtotals;
                        balanceDueTot.Value = total;
                        totalLess.Value = lessTotals;
                        }


                        Then to make the code more C#-like, I would




                        • use var instead of decimal


                        • rename getTotals to GetTotals


                        • use_camelCase for private fileds (so Less becomes _less)

                        • reduce redundant parenthesis from (subtotals - lessTotals)

                        • use brackets {} for the return statement


                        Notice that I also grouped the update of the UI at the end of the method.



                        I would have some comments also for the name of the method itself as GetTotals implies that the method returns something, but the return signature is void. One idea is to use something like CalculateTotals.






                        share|improve this answer

























                          up vote
                          4
                          down vote










                          up vote
                          4
                          down vote









                          Assuming the fields have definitions like the following



                          public class TextboxControl
                          {
                          public object Value { get; set; }
                          }

                          public class CheckboxControl
                          {
                          public bool Checked { get; set; }
                          }


                          I would create some extensions for them in order to reduce code duplication and increase readability, and pretty much this is the core idea.



                          public static class ControlsExtensions
                          {
                          public static bool HasValue(this TextboxControl source)
                          => decimal.TryParse(source.Value.ToString(), out _);

                          public static decimal GetValue(this TextboxControl source)
                          => decimal.Parse(source.Value.ToString());

                          public static decimal GetOptionalValue(this TextboxControl source, CheckboxControl checkbox)
                          {
                          if (checkbox.Checked)
                          {
                          decimal value = decimal.TryParse(source.Value.ToString(), out value) ? value : 0;
                          return value;
                          }
                          return default(decimal);
                          }
                          }


                          Then my next step in refactoring would to use these extensions and rearrange a bit the lines to increase cohesion



                          private void getTotals()
                          {
                          //Check if we have some valid numbers, stop if we don't
                          if ( !curPurc1.HasValue()
                          || !curPurc2.HasValue()
                          || !curPurc3.HasValue()
                          || !curPurc4.HasValue()
                          || !curItem1Tot.HasValue()
                          || !curItem2Tot.HasValue()
                          || !curItem3Tot.HasValue()
                          || !curItem4Tot.HasValue()
                          || !LessItem1Cost.HasValue()
                          || !LessItem2Cost.HasValue()
                          || !LessItem3Cost.HasValue()
                          || !LessItem4Cost.HasValue()
                          || !LessItem5Cost.HasValue()
                          )
                          return;

                          //Add up some values which are always part of the subtotal and then the ditemx ones, which will be 0 or set to a numerical value depending if the checkbox is checked
                          decimal subtotals = curPurc1.GetValue() + curPurc2.GetValue() + curPurc3.GetValue()
                          + curPurc4.GetValue() + curItem1Tot.GetValue() + curItem2Tot.GetValue()
                          + curItem3Tot.GetValue() + curItem4Tot.GetValue()
                          + Item1RateYN.GetOptionalValue() + Item2RateYN.GetOptionalValue() + Item3RateYN.GetOptionalValue() + Item4RateYN.GetOptionalValue();

                          //Get total minus the cost of the property (curPurc1d)
                          decimal plusSubTotal = subtotals - curPurc1.GetValue();


                          //add up all the "less" items to know how much to reduce by
                          decimal lessTotals = LessItem1Cost.GetValue() + LessItem2Cost.GetValue() + LessItem3Cost.GetValue() + LessItem4Cost.GetValue() + LessItem5Cost.GetValue();

                          //Total Balance due
                          //subtotal minus the 'less' values total
                          decimal total = (subtotals - lessTotals);

                          //update the relevant UI field
                          costPlusSubTotal.Value = plusSubTotal;
                          subtotal.Value = subtotals;
                          balanceDueTot.Value = total;
                          totalLess.Value = lessTotals;
                          }


                          Then to make the code more C#-like, I would




                          • use var instead of decimal


                          • rename getTotals to GetTotals


                          • use_camelCase for private fileds (so Less becomes _less)

                          • reduce redundant parenthesis from (subtotals - lessTotals)

                          • use brackets {} for the return statement


                          Notice that I also grouped the update of the UI at the end of the method.



                          I would have some comments also for the name of the method itself as GetTotals implies that the method returns something, but the return signature is void. One idea is to use something like CalculateTotals.






                          share|improve this answer














                          Assuming the fields have definitions like the following



                          public class TextboxControl
                          {
                          public object Value { get; set; }
                          }

                          public class CheckboxControl
                          {
                          public bool Checked { get; set; }
                          }


                          I would create some extensions for them in order to reduce code duplication and increase readability, and pretty much this is the core idea.



                          public static class ControlsExtensions
                          {
                          public static bool HasValue(this TextboxControl source)
                          => decimal.TryParse(source.Value.ToString(), out _);

                          public static decimal GetValue(this TextboxControl source)
                          => decimal.Parse(source.Value.ToString());

                          public static decimal GetOptionalValue(this TextboxControl source, CheckboxControl checkbox)
                          {
                          if (checkbox.Checked)
                          {
                          decimal value = decimal.TryParse(source.Value.ToString(), out value) ? value : 0;
                          return value;
                          }
                          return default(decimal);
                          }
                          }


                          Then my next step in refactoring would to use these extensions and rearrange a bit the lines to increase cohesion



                          private void getTotals()
                          {
                          //Check if we have some valid numbers, stop if we don't
                          if ( !curPurc1.HasValue()
                          || !curPurc2.HasValue()
                          || !curPurc3.HasValue()
                          || !curPurc4.HasValue()
                          || !curItem1Tot.HasValue()
                          || !curItem2Tot.HasValue()
                          || !curItem3Tot.HasValue()
                          || !curItem4Tot.HasValue()
                          || !LessItem1Cost.HasValue()
                          || !LessItem2Cost.HasValue()
                          || !LessItem3Cost.HasValue()
                          || !LessItem4Cost.HasValue()
                          || !LessItem5Cost.HasValue()
                          )
                          return;

                          //Add up some values which are always part of the subtotal and then the ditemx ones, which will be 0 or set to a numerical value depending if the checkbox is checked
                          decimal subtotals = curPurc1.GetValue() + curPurc2.GetValue() + curPurc3.GetValue()
                          + curPurc4.GetValue() + curItem1Tot.GetValue() + curItem2Tot.GetValue()
                          + curItem3Tot.GetValue() + curItem4Tot.GetValue()
                          + Item1RateYN.GetOptionalValue() + Item2RateYN.GetOptionalValue() + Item3RateYN.GetOptionalValue() + Item4RateYN.GetOptionalValue();

                          //Get total minus the cost of the property (curPurc1d)
                          decimal plusSubTotal = subtotals - curPurc1.GetValue();


                          //add up all the "less" items to know how much to reduce by
                          decimal lessTotals = LessItem1Cost.GetValue() + LessItem2Cost.GetValue() + LessItem3Cost.GetValue() + LessItem4Cost.GetValue() + LessItem5Cost.GetValue();

                          //Total Balance due
                          //subtotal minus the 'less' values total
                          decimal total = (subtotals - lessTotals);

                          //update the relevant UI field
                          costPlusSubTotal.Value = plusSubTotal;
                          subtotal.Value = subtotals;
                          balanceDueTot.Value = total;
                          totalLess.Value = lessTotals;
                          }


                          Then to make the code more C#-like, I would




                          • use var instead of decimal


                          • rename getTotals to GetTotals


                          • use_camelCase for private fileds (so Less becomes _less)

                          • reduce redundant parenthesis from (subtotals - lessTotals)

                          • use brackets {} for the return statement


                          Notice that I also grouped the update of the UI at the end of the method.



                          I would have some comments also for the name of the method itself as GetTotals implies that the method returns something, but the return signature is void. One idea is to use something like CalculateTotals.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited 5 hours ago

























                          answered 5 hours ago









                          Adrian Iftode

                          269111




                          269111






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Code Review Stack Exchange!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              Use MathJax to format equations. MathJax reference.


                              To learn more, see our tips on writing great answers.





                              Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                              Please pay close attention to the following guidance:


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209540%2fcalculate-subtotals-and-totals-from-a-form-with-many-decimal-values%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              What visual should I use to simply compare current year value vs last year in Power BI desktop

                              How to ignore python UserWarning in pytest?

                              Alexandru Averescu