REAL-WORLD COMPUTER PROGRAMMING FOR KIDS
STEP 25: TRIPPING ON THE STEPS, AND ANOTHER ROUND OF REFACTORING
In the Last Step, we left off with the question as to whether we should do one of two things to try to fix the bug we’re chasing. The first option was to remove the “+ 1” from this line of code:
freezeAnswer = MultipleChoiceClassIndex + 1 == numberOfQuestions;
I ran the code again with that change, and it did solve that particular problem (the Label now goes from “Question 9 of 10” to “Question 10 of 10” instead of jumping from “Question 9 of 10” to “Question 11 of 10”). Good!
However (as mentioned earlier, there is usually a “However”), on taking a fresh look at how the code was organized, I noticed that it was a bit “scattered” and convoluted. For example, the freezeAnswer variable is assigned before it needs to be. It is assigned near the start of the LoadNextBatch method, but its value is not referenced – that is to say, nothing is done with it – until much later. Since its value is based on the State of global variables (accessible from anywhere within Form1.cs), it makes more sense to assign its value just before referencing it, rather than way ahead of time. So I moved that line of code from where it was to the CheckedChanged Event Handler of the Radio Buttons, just before it is referenced:
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
freezeAnswer = MultipleChoiceClassIndex == numberOfQuestions;
if (freezeAnswer)
. . .
And because the code seems to be a bit haphazard, it’s time for another round of Refactoring.
Let’s get back to basics, and think about just what it is our app is doing, from the point where the user begins to interact with it.
1) They select a CSV file from the Combo Box.
2) That CSV file is loaded into a List, with each item (Class Instance) in the List holding a set of Question, Candidate Answers, and which Answer is correct.
3) The first Question and Candidate Answers are populated in a Label and the Radio Buttons’ Text properties; the Label above the Progress Bar also becomes “Question 1 of 10” (or however many questions the CSV file holds).
4) The user selects an Answer from among the Radio Buttons (and can keep selecting/changing their mind until they click the “Next” Button)
5) When ready for the next Question, the user selects the “Next” Button
-- then it all repeats from #3 (but replace “first Question” with “next Question”) until another file is selected, when #1 and #2 repeat, before continuing on.
The only change in this repeating process is once the last Question is reached. At that point, selecting a Candidate Answer acts as the “Next” Button has until now – but as there are no more Questions to ask, the last Question and the Answers remain the same (until the user selects a new CSV file from the Combo Box).
Fairly simple, really. So we should be able to make the code simple and straightforward, too.
It seems like all the updating of the Form should be done in one place, don’t you think? There should be one method dedicated to doing just that.
So, besides the Event Handlers (particularly 1) Selecting an answer among the Radio Buttons, and 2) Clicking the “Next” Button, there should basically just be two other major methods – the one that loads the CSV file after the user selects it from the Combo Box, and the one to update the form with each new question.
The method that loads the selected CSV file already exists, in the form of the SelectedIndexChanged Event Handler method. But since the name cmbxSelectMultiChoiceFile_SelectedIndexChanged doesn’t imply what its code currently does, let’s create a method with that name and then call it from the SelectedIndexChanged Event Handler.
To do that, create a method named PopulateList, just below the cmbxSelectMultiChoiceFile_SelectedIndexChanged Event Handler method. It should look like this:
private void PopulateList()
{
}
Now copy all the code from the cmbxSelectMultiChoiceFile_SelectedIndexChanged Event Handler method into there (everything between the curly braces), and call the PopulateList method from the temporarily empty SelectedIndexChanged Event Handler. The Event Handler method should now be:
private void cmbxSelectMultiChoiceFile_SelectedIndexChanged(object sender, EventArgs e)
{
PopulateList();
}
Note: This change may have seemed rather timewastical, but having methods with descriptive names helps you to remember to only put code in that method that matches its name. If you start going off on a tangent and doing other things in there, you are (hopefully) reminded to move that stuff out into a separate method.
Looking through it closely, there is an extraneous call in our new PopulateList method – when it calls LoadNextBatch. We could change the name of the new method to “PopulateListAndLoadFirstSetOfRecords” or something, but that’s a bit long-winded, and goes against the programming principle of having a method do only one thing. So let’s move that call from PopulateList to the SelectedIndexChanged Event Handler, so that it is now:
private void cmbxSelectMultiChoiceFile_SelectedIndexChanged(object sender, EventArgs e)
{
PopulateList();
LoadNextBatch();
}
In fact, we could (and should) make the Event Handler a little safer by practicing “Defensive Coding,” preparing ourselves for “unexpected things that might happen.” So let’s surround our code with a “try...catch” block, so that it ends up like this:
private void cmbxSelectMultiChoiceFile_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
PopulateList();
LoadNextBatch();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
}
All right; that ended up being quite a makeover – or at least a non-trivial one. Now, as for the method to update the Form with each new question, we basically already have it, but it’s named LoadNextBatch (the method we were just talking about). But, on second thought, that’s kind of an unfortunate name. LoadNextBatch of what? Ginger Snaps (AKA Molasses cookies)? I wish! To avoid the vagueness (and the temptations of the thoughts that it invokes), let’s change the name of the method to UpdateTheForm.
Note: It is good software design to give methods descriptive names. And if you first follow the tenet that each method should only do one thing (we had gotten away from that a little), naming it should be pretty easy. Just ask yourself: What does this method do? In this case, we could say, “It updates the Form.” So UpdateTheForm is a logical choice.
Change the name of the method this way:
1) Go to the LoadNextBatch method in the code
2) Select the name of the method with your clicker (mouse), right-click, and select Rename from the context menu. You will see this:

Note how the screenshot implies that it will rename all the references to LoadNextBatch for us? That’s one of the myriad ways that Visual Studio aims to please by helping you out where it can (without getting in the way, like Word Processors want to do by trying to guess what you are writing and erroneously finishing words for you).
3) With LoadNextBatch highlighted, change it to “UpdateTheForm”
4) Select the “Apply” Button in the “Rename: LoadNextBatch” Dialog.
Voila! (which is French for “Wallaby”); I don’t know why they say that.

Photo of “Voila-bee” by benjamint / CC BY-SA (http://creativecommons.org/licenses/by-sa/3.0/)
Now it’s time for another “Desk Check” (which, if you remember, means we gawk at our code on the screen, trying to locate any obvious mistakes or oversights), and marveling in the wonder of it all. Sometimes.
I’ll give you however long you want to do that...
Aha! Note this code in the section of the newly-renamed PopulateList method:
else // if mccList already exists, remove its items from previous file
{
mccList.Clear();
// ...and update progress controls
lblQuestionNOfN.Text = originalQuestionNofN;
lblPercentage.Text = originalPercentageStr;
progressBar1.Value = 0;
}
What does everything after mccList.Clear() have to do with Populating the List?
Answer: Ganz und gar nichts! (That’s German for “Nothing at all!” (really!))
So, we will move that code out to a separate method. Since this is done when we are “starting fresh” with a new set of Questions, let’s name this method “InitializeForm.”
For now, move those three lines of code into the new InitializeForm method; we may find other things that belong there later. It should look like this:
private void InitializeForm()
{
lblQuestionNOfN.Text = originalQuestionNofN;
lblPercentage.Text = originalPercentageStr;
progressBar1.Value = 0;
}
Don’t forget to call InitializeForm from where those lines of code used to be. That snippet of code we looked at earlier should now be:
else // if mccList already exists, remove its items from previous file
{
mccList.Clear();
InitializeForm();
}
Also, I moved the call to UpdatePercentageCorrect from the “Next” Button’s Click Event Handler to the UpdateForm method.
So the Click Event Handler is now simply this:
private void button1_Click(object sender, EventArgs e) // "Next" button
{
if (questionsAnswered < numberOfQuestions)
{
questionsAnswered++;
}
if (questionsAnswered == numberOfQuestions) return;
UpdateTheForm();
}
...and the UpdateTheForm method now calls UpdatePercentageCorrect, here:
if (MultipleChoiceClassIndex < numberOfQuestions)
{
UpdateQuestionNumberLabel();
UpdatePercentageCorrect();
. . .
There’s another couple of things I noticed that would make the app easier to understand, namely to restrict the count of numbers after the decimal point in the percentage Label to 2, and to append “(N of N”) to that percentage Label so users don’t get confused between how many Questions they have answered and which one they are currently on. For example, after three answers, those Labels above the Progress Bar could read, “Question 4” and “66.67% (2 of 3)”
So before returning to Stepping Through the Code, let’s take care of those two things “real quick,” as they say.
To restrict the count of numbers displayed past the decimal point in the Percentage Label (lblPercentage), and to then append a “(N of N)” explanatory note to that string, change this code in UpdatePercentageCorrect:
lblPercentage.Text = percentageCorrect.ToString() + "%";
to:
double prcntg = Math.Round(percentageCorrect, 2);
lblPercentage.Text = string.Format(prcntg.ToString() + "% ({0} of {1})", correctAnswers, questionsAnswered);
The call to Math.Round() and the “2” argument restricts the real value to two integers, such as “3.14” instead of “3.14159265359”; Our old friend, the string.Format() utility method replaces the placeholders with the current values of the two int variables passed to it (correctAnswers and questionsAnswered), so lblPercentage could end up displaying, for example, “83.33% (5 of 6).
Some of you are whinging, “When are we going to get back to Stepping through the code?!?” and can relate to some of these dogs:

Well, your whininesses (and you others who persevered stoically, yearning for more stepping but intrepidly marching forth, valiant while in duress and uncomplaining although beset by a myriad maladies), in our next Step, we will get back to stepping through the code.
We have refactored it to make it more sensible and understandable, but whether it works exactly as we need it to remains to be seen. We will find out in the next installment in the one and only Computer Programming for Kids Journey that exists in the entire Universe ... as far as we know, anyway.
Until then!
NO MATTER WHAT YOU DO, DON’T READ THIS: The first volume of my four-volume series, Real-World Computer Programming for Kids of All Ages, namely Volume 1: Windows Forms Apps Using C# and Visual Studio is now available in both Paperback and Kindle formats. Volume 1 contains everything that has been printed in this Newsletter so far and through Step 34.
The kindle version of the book can be accessed here: https://www.amazon.com/dp/B08H7DKKCS/ and the Paperback version can be accessed here https://www.amazon.com/dp/B08H9RB1WG/

Earth-shakingly Important Notice: If you have a basic programming question (suitable to an audience of “Kids”), send it to idiolectable@gmail.com, specifying whether you would like your name and location used if it is printed in a future “Step” of this newsletter. If you are a subscriber to the newsletter, you can also leave a question at the bottom of this Step, in the “Comments” section.
If you do not want to give your real name, a nickname is acceptable (the first “Letter to the Editor” of mine that was printed appeared in Rolling Stone magazine, back in the early 1970s, and I signed it “Sylvester” for some reason which I no longer remember).
Finally, it’s always interesting to see where people are from, so please provide your City or Town and the State it’s in, too (or Province, or whatever the region where you live is called).
To listen to this Step, the audio of it can be found here: