0

Here's what I'm trying to do. I have a form with several checkboxes. The user will check 1 or 2 or 12 of them, and then click a button and then several things will happen, depending on which boxes were checked.

    private void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBox1.Checked == true)
        {
            checkBox1.Tag = "IP";
            Console.WriteLine(checkBox1.Tag);
        }
        else
        {
            checkBox1.Tag = null;
        }
    }
    private void CheckBox2_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBox2.Checked == true)
        {
            checkBox2.Tag = "PR";
            Console.WriteLine(checkBox2.Tag);
        }
        else
        {
            checkBox2.Tag = null;

        }
    }

So that's just a sample of the code for 2 of the 24 checkboxes I have on this form. Once the user clicks the button, the form will save a file using the checkboxX.Tag variable:

        private void button2_Click(object sender, EventArgs e)
    {

        if (string.IsNullOrWhiteSpace(myFile) &
            string.IsNullOrWhiteSpace(selectDate) &
            string.IsNullOrWhiteSpace(selectDept))
        {
            MessageBox.Show("Well, that didn't work. Check your info and try again!");
            return;
        }
        else File.Exists(myFile);
        {
            MessageBox.Show("Document(s) added! " + selectDept + selectWorker +
              " for " + dateTime.Year + "-" + dateTime.Month + "-" + dateTime.Day);
            MessageBox.Show("To add more docs, re-open this program");
            if (checkBox1.Checked)
            {
                string finalName = @"C:\testing\" + selectDept + selectWorker + @"\" + 
                  checkBox1.Tag + dateTime.Year + dateTime.Month + dateTime.Day + ".pdf";
                textBox2.Text = finalName;
                File.Copy(myFile, finalName, true);
            }
            if (checkBox2.Checked)
            {
                string finalName = @"C:\testing\" + selectDept + selectWorker + @"\" + 
                  checkBox2.Tag + dateTime.Year + dateTime.Month + dateTime.Day + ".pdf";
                textBox2.Text = finalName;
                File.Copy(myFile, finalName, true);
            }

So, as it stands, it works for the first and only the first checkbox. Like, the file will copied and saved just like it's supposed to, but instead of having 5 identical files named "IP20181012", "PR20181012", "FS20181012" and so on, I end up with one file named "IP20181012", and then one other file just named "20181012", making me believe that the checkBox2.Tag variable is never set. I've tried using a separate variable (other than the built-in checkBox1.Tag one), and the exact same problem happens. It seems like only checkBox1.Tag will get set properly while the other checkBoxX.Tag variables all stay null. Even when I declared separate varaibles and then tried to set them in the checkboxes, only the one for checkBox1 will ever be set, no matter what I do.

Also, is this an okay way to use if statements? I don't need them nested. Can I just kinda line them up so that clicking the button will just run through all of the if statements underneath it?

Ryan Lundy
  • 204,559
  • 37
  • 180
  • 211
TnD_Guy
  • 113
  • 1
  • 2
  • 13
  • Does the console.writeline(checkBox2.Tag) output anything to the console? – Nick Nov 05 '18 at 16:38
  • No it does not. But the checkBox1.Tag does. That's what is so strange. – TnD_Guy Nov 05 '18 at 16:39
  • Is the CheckBox2 event wired up? What happens when you debug the code? – LarsTech Nov 05 '18 at 16:41
  • Why are you setting the `.Tag` in a checked event? Is there something else that sets the `.Tag` to something else? Why is it not just a compile-time constant? – Ron Beyer Nov 05 '18 at 16:44
  • Is there any need to dynamically set the Tag property based on the user clicking the check box? In other words, could you just set the Tag for each check box in the form designer (e.g. CheckBox1 has Tag property "IP", CheckBox2 has Tag property "RP" etc...). Unless Tag needs to be null for other functionality on the form? – Alistair Findlay Nov 05 '18 at 16:45
  • I cannot recreate this using your code. It works fine. However, I did have to "wire up" the events first. Remember to put breakpoints in your code to see the values of variables as the program runs. – Syntax Error Nov 05 '18 at 16:50
  • @SyntaxError Okay, so I feel dumb asking this, but how do I use breakpoints to see the values of variables as the program runs? That would be so helpful. I tried to have it write to the Console so that at least I can look at the console AFTER the program runs. – TnD_Guy Nov 05 '18 at 17:04
  • @TnD_Guy Not a stupid question! Find a line you want to stop at. Press `F9` and it'll turn red, creating what is called a breakpoint. Run the program in debug mode (`F5`) and try to get to the code you marked with `F9`. At the bottom of VisualStudio there's a button called `Locals`. From there you can view and expand all your objects and see the values of various properties as they are set on that line. Keep pressing F5 to move onto the next breakpoint and see your variables change as the program executes. – Syntax Error Nov 05 '18 at 18:00

4 Answers4

1

A bunch of if statements in the button's click handler is a good way to do it. And you won't even need to use the Tag property or handle the checkbox checked events anymore because you are checking the checked property anyway.

    if (checkBox1.Checked)
    {
        string finalName = @"C:\testing\" + selectDept + selectWorker + @"\IP"
            + dateTime.Year + dateTime.Month + dateTime.Day + ".pdf";
        textBox2.Text = finalName;
        File.Copy(myFile, finalName, true);
    }
    if (checkBox2.Checked)
    {
        string finalName = @"C:\testing\" + selectDept + selectWorker + @"\PR"
          + dateTime.Year + dateTime.Month + dateTime.Day + ".pdf";
        textBox2.Text = finalName;
        File.Copy(myFile, finalName, true);
    }
Leo Bartkus
  • 1,925
  • 13
  • 17
  • I feel like such a derp. This is the most obvious and easiest answer and I was so hung up on setting cool/fancy variables that it hadn't even occurred to me to just do it this way. – TnD_Guy Nov 05 '18 at 17:11
  • 1
    If you are going to do something like this, try to reduce all the repeated code. Whenever you copy/paste that much code, it's a _code smell_. Take a look at my answer (which has just one of these `if` blocks) for some ideas on rationalizing things. – Flydog57 Nov 05 '18 at 17:49
0

How did you create the event handlers for these checkboxes?

Did you double-click on each checkbox?

Or did you double-click on one, create the event handler, and then copy-and-change that one for each of the others?

What happens that you can't see is that in the code-behind file (MyForm.Designer.cs), there's a line for each event handler that looks like this:

this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged);

That's the line that actually wires up the event. Without that line, your checkbox isn't actually going to respond to anything.

If you started in VB6 or VBA, then it's a bit confusing because in those languages, just creating a method with the right name would magically cause this wiring-up to happen. But in C# (and VB .NET) it's explicit, even though it may be hidden in the Designer file.

But you can also add these lines yourself. This is the way I always do it, so the Designer isn't hiding things. In the constructor of your form, you can type them this way:

public MyForm()
{
    checkBox1.Checked += checkBox1_Checked;
    checkBox2.Checked += checkBox2_Checked;
    [etc.]
}
Ryan Lundy
  • 204,559
  • 37
  • 180
  • 211
  • I think this might be what I did wrong, but when I enter ' checkBox2.Checked += checkBox2_Checked;' I get an error that says "The name 'checkBox2_Checked' does not exist in the current context". I get a similar error when I try to manually enter it on the Form1.Designer.cs side. – TnD_Guy Nov 05 '18 at 16:58
  • In the code above, you have it capitalized: `CheckBox2_CheckedChanged`. C# is case-sensitive. Try changing either the wire-up line or the method name. – Ryan Lundy Nov 05 '18 at 17:01
  • @TnD_Guy You might also consider posting the code on codereview.stackexchange.com where people can help you find more efficient ways (= less code) to do what you're doing. – Ryan Lundy Nov 05 '18 at 17:06
  • I like that code review idea. In case you can't tell, I'm brand-freaking new to coding and I'm working off of YouTube tutorials and google searches. Websites like this are great because most of questions have already been asked by someone else! Thank you for your help :) – TnD_Guy Nov 05 '18 at 17:15
  • @TnD_Guy, if any of the answers are helpful, you can indicate that by up-voting them. And you can accept an answer (the checkbox) if it solved your problem. This helps other visitors who may be having the same problem and are searching for a fix. – Ryan Lundy Nov 05 '18 at 17:20
  • I have one more question related to this topic. Is there a way that I can ask it? I suppose I can edit my original question, but I'm concerned that no one will see my edit since my original question has already been answered. – TnD_Guy Nov 05 '18 at 17:34
0

Coding a cleaner code will make things easier. Some suggestions:

  1. Instead of directly using your checkboxes, create a Class ("CheckBoxConfigs.cs" that will have boolean/string flags regarding the checkbox functionality (your code will be easier to read/mantain);

  2. Make all your checkboxes use the same handler (the same "event" function), where you can setup your "CheckBoxConfigs.cs" flags (instead of using "tag" property you would have a class with the role to handle the flags) instead of creating code for 24 CheckBox_CheckedChanged functions;

Zoe
  • 27,060
  • 21
  • 118
  • 148
Felipe Torres
  • 292
  • 2
  • 10
  • First, set the `Tag` property of each checkbox in the WinForms designer. If you don't need to output something via `Console.WriteLine`, then you don't even need a single `CheckChanged` event handler. All you need to do is use or not use the pre-configured `Tag` property based on the `CheckedProperty` – Flydog57 Nov 05 '18 at 16:52
  • I want to do this, but I suppose I need to read up on classes a bit more. I sort of understand how to use them. I was thinking an array might also be useful here? Since each event identical except for a couple of variables that will be determined by the check boxes. – TnD_Guy Nov 05 '18 at 16:53
  • @Flydog57 When I deleted the CheckChanged handlers in the code, I get an error in the Form1.Designer.cs thing. – TnD_Guy Nov 05 '18 at 16:54
  • deleting in the code without setting in the property window usually make this error. Probably the best way is clean the handlers in the property window, then setting up manually. Check https://stackoverflow.com/questions/803242/understanding-events-and-event-handlers-in-c-sharp – Felipe Torres Nov 05 '18 at 17:01
  • Yeah, when you set up a handler, the designer writes code in the .designer.cs file to do the wire-up and also writes a shell of the handler in the regular .cs file (for you to modify). If you delete the handlers only in the .cs file, then the code in the designer file is referring to a function that no longer exists. You can cheat and just (carefully) delete the line that does the wireup (`someControl.CheckChanged += new System.EventHandler(this.someControl_CheckChanged)`). The better way to do this is to go into the designer's event view and delete the handler ffrom there. – Flydog57 Nov 05 '18 at 17:14
0

First set the Tag property for each checkbox in the designer to the strings you want. Then, get rid of the CheckChanged handlers. Finally, do something like this in you button handler (I've made obvious modifications (like I don't call File.Copy)):

 private void button2_Click(object sender, EventArgs e)
 {
     var selectDept = "MyDept";
     var selectWork = "MyWork";
     var myFile = @"c:\somefolder\somefile.ext";
     var dateTime = DateTime.Now;

     var formattedDate1 = dateTime.ToString("yyyy-MM-dd");
     var formattedDate2 = dateTime.ToString("yyyyMMdd");
     MessageBox.Show($"Document(s) added {selectDept}{selectWork} for {formattedDate1}");
     var checkboxes = new[]
     {
         checkBox1,
         checkBox2,
         checkBox3,
         //you get the idea
     };
     foreach (var checkbox in checkboxes)
     {
         if (checkbox.Checked)
         {
             var finalName = $@"C:\testing\{selectDept}{selectWork}\{checkbox.Tag}{formattedDate2}.pdf";
             textBox1.Text = finalName;      //no sure what this is for
             Debug.WriteLine($"MyFile: [{myFile}], Final Name: [{finalName}]");
         }
     }
 }

If I check the first and third checkboxes (whose Tag properties are "CK1" and "CK2", I get the following in my output:

MyFile: [c:\somefolder\somefile.ext], Final Name: [C:\testing\MyDeptMyWork\CK120181105.pdf]
MyFile: [c:\somefolder\somefile.ext], Final Name: [C:\testing\MyDeptMyWork\CK320181105.pdf]

I think that's pretty close to what you want

Flydog57
  • 6,851
  • 2
  • 17
  • 18