0
\$\begingroup\$

so I've made a simple program meant to increase and decrease numbers, then save those numbers, basically a rubbish stock taking app, I want to make one I can use and well it's usable I'd say the code isn't refined enough to take it from this little program to a bigger better one. I want to make one because I want to practice programming more and I want a simple program that works well with a tablet. I'm wondering if there is a better way to program the buttons and the way it saves and loads more efficiently I don't want every button to have the same code but I can't seem to figure out how. Thanks

This was done with C# in Windows forms

The top section of my code saves it, the middle loads it and the long repetitive end are all the buttons, there is also an attempt to make a timer in there

Code in text:

using (StreamWriter outputfile = new 
           StreamWriter($@"SaveData.txt"))
    {

        //Loads the stuff from the last session

        string OutPut = Item1.Text + "\n" + Amount1.Text + "\n" + Item2.Text + "\n" + Amount2.Text + "\n" + Item3.Text + "\n" + Amount3.Text
            + "\n" + Item4.Text + "\n" + Amount4.Text + "\n" + Item5.Text + "\n" + Amount5.Text + "\n" + Item6.Text + "\n" + Amount6.Text;

        outputfile.WriteLine(OutPut);
    };

    z
    Save.Text = "Saved";

    //My attempt to make a timer v
    {
        /*

         My attempt at making the saved button count up. 

           for (int a = 0; a < 60; a++)
        {
            int savedSince = a;

            Save.Text = "Saved" + " " + Convert.ToString(savedSince);

            Task.Delay(1000);
        }

        Save.Text = "Saved <1 Min";

        */
    }
}

private void Load_Click(object sender, EventArgs e)
{
    using (StreamReader inputfile = new StreamReader($@"SaveData.txt"))
    {

        //This is to load everything by reading the text file line by line for each thing.

        Item1.Text = inputfile.ReadLine();
        Amount1.Text = inputfile.ReadLine();

        Item2.Text = inputfile.ReadLine();
        Amount2.Text = inputfile.ReadLine();

        Item3.Text = inputfile.ReadLine();
        Amount3.Text = inputfile.ReadLine();

        Item4.Text = inputfile.ReadLine();
        Amount4.Text = inputfile.ReadLine();

        Item5.Text = inputfile.ReadLine();
        Amount5.Text = inputfile.ReadLine();

        Item6.Text = inputfile.ReadLine();
        Amount6.Text = inputfile.ReadLine();
    }

}

/*
The first one adds 1 to the count by taking the text box and turning it into an int 
then taking the new int and turning it into a string and replacing the text box with it, 
same for the second one but it takes one off, then it repeats for the next two buttons 
and so on
*/

private void Add1_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount1.Text) + 1;

    Amount1.Text = Convert.ToString(amount);
}

private void Decrease1_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount1.Text) - 1;

    Amount1.Text = Convert.ToString(amount);
}

private void Add2_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount2.Text) + 1;

    Amount2.Text = Convert.ToString(amount);
}

private void Decrease2_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount2.Text) - 1;

    Amount2.Text = Convert.ToString(amount);
}

private void Add3_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount3.Text) + 1;

    Amount3.Text = Convert.ToString(amount);
}

private void Decrease3_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount3.Text) - 1;

    Amount3.Text = Convert.ToString(amount);
}

private void Add4_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount4.Text) + 1;

    Amount4.Text = Convert.ToString(amount);
}

private void Decrease4_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount4.Text) - 1;

    Amount4.Text = Convert.ToString(amount);
}

private void Add5_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount5.Text) + 1;

    Amount5.Text = Convert.ToString(amount);
}

private void Decrease5_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount5.Text) - 1;

    Amount5.Text = Convert.ToString(amount);
}

private void Add6_Click(object sender, EventArgs e)
{
    int amount = Convert.ToInt32(Amount6.Text) + 1
\$\endgroup\$
1
  • 1
    \$\begingroup\$ The current question title, which states your concerns about the code, applies to too many questions on this site to be useful. The site standard is for the title to simply state the task accomplished by the code. Please see How do I ask a good question?. \$\endgroup\$
    – BCdotWEB
    Commented Dec 14, 2021 at 8:47

2 Answers 2

2
\$\begingroup\$

@jdt gave a decent answer and I particularly like the closing statement of using a DataGridView. For now, let's look at other alternative techniques using text boxes.

To output the values to to text file, you can try

var boxes = new List<TextBox>()
{ 
    Item1, Amount1,
    Item2, Amount2,
    Item3, Amount3,
    Item4, Amount4,
    Item5, Amount5
};

string output = String.Join(Environment.NewLine, boxes.Select(x => x.Text));

File.WriteAllText("SaveData.txt", output);

This uses the more proper Environment.NewLine , which is a new line AND carriage return. It also is OS independent so your app would run smoothly on Linux as well as Windows.

There is no need for a using since we output the contents all at once.

To Add or Decrease Amounts by 1

private void UpdateAmount(TextBox amountBox, int adjustment)
{
    int amount = Convert.ToInt32(amountBox.Text) + adjustment;
    amountBox.Text = amount.ToString();
}

private void Add1_Click(object sender, EventArgs e) => UpdateAmount(Amount1, 1);
private void Decrease1_Click(object sender, EventArgs e) => UpdateAmount(Amount1, -1);
// Repeat for Amount2 - 4
private void Add5_Click(object sender, EventArgs e) => UpdateAmount(Amount5, 1);
private void Decrease5_Click(object sender, EventArgs e) => UpdateAmount(Amount5, -1);

Most C# developers would prefer to use the simple amount.ToString() rather than Convert.ToString(amount).

\$\endgroup\$
1
  • \$\begingroup\$ I tried DataGridView first but I couldn't quite figure out DataBase, DataGridView also wasn't giving me the layout I was looking for. Your code here is perfect though and also extremely helpful for other things. I've tried to figure out how to do the exact thing you've suggested for the buttons a few times before and could never find anything I was looking for. The saving text is great too. This is pretty much exactly what I was looking for. Took me a minuet to understand the code, but I've gotten it now. Thanks for your reply \$\endgroup\$ Commented Dec 20, 2021 at 22:48
2
\$\begingroup\$

You can create the event handlers dynamically instead of hard coding them. The following will add events handlers for all the Add and Decrease buttons:

private void Form1_Load(object sender, EventArgs e)
{
    foreach (var ctrl in Controls)
    {
        var control = (Control)ctrl;
        if (control.Name.StartsWith("Add") || control.Name.StartsWith("Decrease"))
            control.Click += buttonClicked;
    }
}

private Control getAssociatedControl(Control control, string name)
{
    var id = string.Concat(control.Name.ToArray().Reverse().TakeWhile(char.IsNumber).Reverse());
    return Controls[name + id];
}

private void buttonClicked(object sender, EventArgs e)
{
    var control = (Control)sender;
    var textbox = getAssociatedControl(control, "Ammount");
    int increment = control.Name.StartsWith("Add") ? 1 : -1;
    textbox.Text = (int.Parse(textbox.Text) + increment).ToString();
}

You can use the same trick for loading and saving but here you will have to sort them to make sure that they are always in the same order:

private void Load_Click(object sender, EventArgs e)
{
    var dict = new SortedDictionary<string, Control>();
    foreach (var ctrl in Controls)
    {
        var control = (Control)ctrl;
        if (control.Name.StartsWith("Item"))
            dict[control.Name] = control;
    }

    using (StreamReader inputfile = new StreamReader($@"SaveData.txt"))
    {
        foreach (var name in dict.Keys)
        {
            var label = dict[name];
            var textbox = getAssociatedControl(label, "Ammount");
            label.Text = inputfile.ReadLine();
            textbox.Text = inputfile.ReadLine();
        }
    }
}

Add some point you are going to get tired of having hundreds of buttons and text boxes and should consider rather using a DataGridView =)

\$\endgroup\$
1
  • \$\begingroup\$ Can DataGridView have big buttons on it? I want the program to be usable with a tablet and pen which is why I've gone for making buttons so they can be big. I also can't seem to figure out database stuff so if I can't even get the button layout I want then I don't want to spend hours figuring out database \$\endgroup\$ Commented Dec 20, 2021 at 21:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.