Deovi
Deovi

Reputation: 51

C# Add variable to List by iterating name

Is there a way I can add Values to a List by iterating? I have a form with all the variables declared and a class to collect all the information. But I'm trying to learn a way to add all this through code instead of having so much repeated code.

namespace WinForm

{

public partial class Form_Destrezas : Form
{
    //Fields
    Tab_Destreza Personales;
    Tab_Destreza Salud;
    Tab_Destreza Participacion;
    Tab_Destreza Convivencia;
    Tab_Destreza Limpieza;
    Tab_Destreza Alimentos;
    Tab_Destreza Ropa;
    Tab_Destreza Libre;
    Tab_Destreza Futuro;


    public Form_Destrezas()
    {
        Personales.AddRow(Personales_1RowNoApp,
                          Personales_1RowNoDom,
                          Personales_1RowEnPro,
                          Personales_1RowDomina,
                          Personales_1RowCheckBox)

    //What I want to do
        for (int i = 0; i <= 10; i++)
        {
            Personales.AddRow(Personales_[i]RowNoApp,
                          Personales_[i]RowNoDom,
                          Personales_[i]RowEnPro,
                          Personales_[i]RowDomina,
                          Personales_[i]RowCheckBox)
        }


        this.Text = $"Destrezas - {StudentData.Name}";
        InitializeComponent();
    }


    private void Personales_1RowNoDom_CheckedChanged(object sender, EventArgs e)
    {
        Personales.checkRow();
    }
}


/// <summary>
/// Data for each row will be collected here.
/// </summary>
public class RowData
{
    //Fields
    public List<RadioButton> RadioButtons;
    public CheckBox TeacherVerified;
    public string ActiveStatus = "No Applica";
    public bool verified = false;

    //Methods

    /// <summary>
    /// Input row information collection.
    /// </summary>
    /// <param name="noApp">Radiobutton "No Applica" for Row.</param>
    /// <param name="noDom">Radiobutton "No Domina" for Row.</param>
    /// <param name="enProc">Radiobutton "En Processo" for Row.</param>
    /// <param name="domina">Radiobutton "Domina" for Row.</param>
    /// <param name="EviMaestro">CheckBox if was verified.</param>
    public void AddRow(RadioButton noApp, RadioButton noDom, RadioButton enProc,
        RadioButton domina, CheckBox EviMaestro)
    {
        var personalesRows = this.GetType().GetTypeInfo();
        RadioButtons.Add(noApp);
        RadioButtons.Add(noDom);
        RadioButtons.Add(enProc);
        RadioButtons.Add(domina);
        TeacherVerified = EviMaestro;
        checkRow();

    }
    /// <summary>
    /// Collects Data from row.
    /// </summary>
    public void checkRow()
    {

        foreach (var Button in RadioButtons)
        {

            if (Button.Checked)
            {
                ActiveStatus = Button.Text;
            }
        }
        if (TeacherVerified.Checked == true)
        {
            verified = TeacherVerified.Checked;
        }
    }


}

public class Tab_Destreza : RowData
{



}

}

Upvotes: 1

Views: 164

Answers (1)

Mat&#237;as Fidemraizer
Mat&#237;as Fidemraizer

Reputation: 64943

First of all I would build a sequence on which each element would be a map of each row's class field name and their corresponding values:

var personalesRowMaps = this.GetType().GetTypeInfo().GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
        .Where(f => f.Name.StartsWith("Personales_"))
        // f.Name.Split(...) part explained: each field has an underscore,
        // where the next character after it is the row index. Thus, 
        // I split the name using the underscore and I get the right part 
        // of the field identifier, and then I get the first character of
        // that part: the row index.
        .Select(f => new { Index = f.Name.Split('_')[1][0], Field = f })
        .GroupBy(o => o.Index)
        .Select(g => g.ToList().ToDictionary(o => o.Field.Name, o => o.Field.GetValue(this)));

Step by step:

  1. We get all fields from the current class.
  2. We filter out all fields so we could work on ones with the "Personales_" prefix.
  3. We project each found field into an object of two properties: (1) we extract the number (the index) of the row to which the field belongs to (i.e. Personales_1XXX), (2) the reflected class field.
  4. We group all fields by the extracted row index
  5. We project each resulting row index grouped fields into a dictionary, where keys are the field names and the values the field values.

Once you've built that map, adding the whole rows is an easy task. You just need to iterate each dictionary and add each field to Personales, where the row index will be the index of the for loop:

for(int i = 0; i < personalRowMaps.Count; i++)
{
     var rowMap = personalRowMaps[i];

     Personales.AddRow
     (
         rowMap[$"Personales_{i}RowNoApp"],
         rowMap[$"Personales_{i}RowNoDom"],
         rowMap[$"Personales_{i}RowEnPro"],
         rowMap[$"Personales_{i}RowDomina"],
         rowMap[$"Personales_{i}RowCheckBox"]
     );
}

Notes:

  • You need to clarify if the class fields are private, protected or public. For now, I'll think that they're private (see the binding flags on the LINQ query). Please comment out what access modifier have these class fields.
  • Also, I need to know what's the type of those class fields? DataRow, DataColumn, DataCell... or what? I need this to complete the answer, as for now each field value is typed as object... THE OP HAS ALREADY PROVIDED THE REQUIRED INFO!

Upvotes: 1

Related Questions