Access dynamic object by name in a loop - c#

I am new to c# as am a php / js / html developer.
I have 8 switches named relay_1,relay_2,relay_3 etc etc
I need to be able to change the state of these but I would like to do through a for loop so the number is dynamic.
I have tried various methods but to no avail.
Any help would be greatly appreciated.
This is what I would like ( not correct )
for (int i = 0; i < 8; i++)
{
relay_" + i.IsChecked = true;
}

You cannot generate the name of a variable dynamically, but you can create an array of relay objects (the allRelays variable below), and do your operation in a loop, like this:
var allRelays = new {relay_0, relay_1, relay_2, relay_3, relay_4, relay_5, relay_6, relay_7, relay_8};
foreach (var relay in allRelays) {
relay.IsChecked = true;
}

Related

How to add dynamic checkboxes in a Blazor-server app that use a list of booleans?

To clarify my question more I'll first show you add a checkbox using the blazor component library I'm using:
<MudCheckBox #bind-Checked="#Basic_CheckBox1"></MudCheckBox>
#code{
public bool Basic_CheckBox1 { get; set; } = false;
}
the code above creates a checkbox and then toggles the boolean Basic_CheckBox1 to true or false based on if the checkbox is checked or not.
here is my code
#for (int i = 0; i < checkboxNames.Count; i++)
{
<MudCheckBox #bind-Checked="#checkboxBools[i]" Label="#checkboxNames[i]"></MudCheckBox>
}
this code works until I check or uncheck my created checkboxes, then I get the index out of range error, how can I fix this? I need to use a list of booleans because I don't know how many checkboxes I will need until runtime, if there is any other solution please let me know.
Think of it like the bind isn't done there and then in the loop, but later. By the time the bind comes to be done, the value of i is off the end of the array Length, having been incremented repeatedly. Instead, you can save the current value of your loop variable i into another variable, then use that other variable in your bind:
#for (int i = 0; i < checkboxNames.Length; i++)
{
var x = i;
<MudCheckBox #bind-Checked="#checkboxBools[x]" Label="#checkboxNames[i]"></MudCheckBox>
}
checkBoxBools should be an array/list that is the same length (initalized to have the same number of elements as) checkBoxNames.. For example:
string[] checkboxNames = new string[]{"a","b","c"};
bool[] checkboxBools = new bool[3];
Or, if something else is providing a variable number of names:
checkboxNames = context.People.Select(p => p.Name).ToArray();
checkboxBools = new bool[checkBoxNames.Length];
https://try.mudblazor.com/snippet/GamQEFuFIwdRbzEx

How to check if an element exists to not duplicate it in a collection of controls in C#?

I am trying to make list in c# where data is getting from mysql database. I have created code but it seems like duplicating received item how can I pass this without duplicate (or add only once)?
cmpSearchItem[] listItems = new cmpSearchItem[10];
for (int i = 0; i < listItems.Length; i++)
{
listItems[i] = new cmpSearchItem();
listItems[i].Width = container_main.Width;
listItems[i].cmpID = cmpId;
listItems[i].cmpName = cmpName;
listItems[i].cmpDescription = cmpDescription;
listItems[i].cmpMembers = cmpMembers + "/32";
listItems[i].cmpCountry = cmpCountry;
listItems[i].cmpCreated = cmpCreated;
container_main.Controls.Add(listItems[i]);
}
You should verify if the item is not present in the collection before adding it, in case of the collection does not do that for you (check the documentation or the implementation of the method of the class used):
if ( !container_main.Controls.Contains(listItems[i]) )
container_main.Controls.Add(listItems[i]);
Container_main is a collection.
Therefore before doing the .Add simply do an:
if ( container_main.Contains() == false )

c# collections and re-numbering not working as expected

Hi i'm trying to setup simple test data.
I simply want to take a collection which is smallish and make it bigger by add itself multiple times.
After I;ve added them together i want to re-number the property LineNumber
so that there are no duplicates and that it goes in order. 1,2,3,4....
no matter what i try it doesn't seem to work and i cant see the mistake.
var sampleTemplateLine = dataContext.TemplateFileLines.ToList();
*//tired this doesnt work either*
//List<TemplateFileLine> lineRange = new List<TemplateFileLine>();
//lineRange.AddRange(sampleTemplateLine);
//lineRange.AddRange(sampleTemplateLine);
//lineRange.AddRange(sampleTemplateLine);
//lineRange.AddRange(sampleTemplateLine);
var allProducts = sampleTemplateLine
.Concat(sampleTemplateLine)
.Concat(sampleTemplateLine)
.Concat(sampleTemplateLine)
.ToList();
int i = 1;
foreach (var item in allProducts)
{
item.LineNumber = i;
i++;
}
this doesnt seem to work either
//re-number the line number
var total = allProducts.Count();
for (int i =0; i < total; i++)
{
allProducts[i].LineNumber = i+1;
}
PROBLEM: below RETURN 4 when i'm expecting 1
var itemthing = allProducts.Where(x => x.LineNumber == 17312).ToList();
You are adding the same objects multiple times. You wold have to add new objects or clone the ones you have.
The problem is they are pointing the same object. So if you change a property it changes all the pointed objects at the same
You can use Clone method if it exist, if not you can create your own Clone method like in this question.

Getting a string to be a variable name

I found this question but it's being used with an XML file so I don't really understand what is going on.
What I want to do is get my list of objects to get populated in my for loop. Right now I have this:
for (int i = 0; i < dogs.Length; i++)
{
dogs[i] = new Dog();
}
dogs[0].PictureBox = picDog0;
dogs[1].PictureBox = picDog1;
dogs[2].PictureBox = picDog2;
dogs[3].PictureBox = picDog3;
I want to do something like this:
for (int i = 0; i < dogs.Length; i++)
{
dogs[i] = new Dog();
dogs[i].PictureBox = StringToVariable("picDog" + i);
}
PictureBox is a property field in case that makes a difference.
StringToVariable() is the thing I don't know about. I don't even know what it would be called to search for it.
It's impossible to say for sure without a good, minimal, complete code example. But I would expect that the following statement should work in your scenario:
dogs[i].PictureBox = (PictureBox)Controls.Find("picDog" + i, true)[0];
That will search the children of the current control (which I assume in this case is your Form subclass) for each control in turn. This is somewhat inefficient, as it has to search the controls collection for each item, but as long as you have a relatively small number of items, this is likely not a problem.
Depending on how your Form is set up, the following might also work:
string prefix = "picDog";
foreach (PictureBox pictureBox in Controls.OfType<PictureBox>())
{
if (pictureBox.Name.StartsWith(prefix))
{
int index;
if (int.TryParse(pictureBox.Name.Substring(prefix.Length), out index))
{
dogs[index] = pictureBox;
}
}
}
That version inspects each child control just once, attempting to parse an index appended to the initial text of "picDog", and if it's successful, using that index to assign to your array directly. This has the advantage of scaling well to larger lists of controls, but may be overkill in your case.
Note that in both of the above examples I've left out any error checking. In either example, you would probably want to add some kind of handling in case (for the first example) the desired control couldn't be found, or (for the second example) if you find a control for which you can't parse the index, or fail to fill in one of the elements of the dogs array.
If for some reason neither of the above examples seem to work for you, please edit your post so that it includes a better code example.
Sometimes a simple solution can work well. How about this?
var picDogs = new [] { picDog0, picDog1, picDog2, picDog3 };
for (int i = 0; i < dogs.Length; i++)
{
dogs[i] = new Dog();
dogs[i].PictureBox = picDogs[i];
}
You could even do this:
var dogs = new [] { picDog0, picDog1, picDog2, picDog3 }
.Select(picDog => new Dog() { PictureBox = picDog })
.ToArray();

Dynamic Variable Name Use in C# for WinForms

Not sure what is the best way to word this, but I am wondering if a dynamic variable name access can be done in C# (3.5).
Here is the code I am currently looking to "smarten up" or make more elegant with a loop.
private void frmFilter_Load(object sender, EventArgs e)
{
chkCategory1.Text = categories[0];
chkCategory2.Text = categories[1];
chkCategory3.Text = categories[2];
chkCategory4.Text = categories[3];
chkCategory5.Text = categories[4];
chkCategory6.Text = categories[5];
chkCategory7.Text = categories[6];
chkCategory8.Text = categories[7];
chkCategory9.Text = categories[8];
chkCategory10.Text = categories[9];
chkCategory11.Text = categories[10];
chkCategory12.Text = categories[11];
}
Is there a way to do something like ("chkCategory" + i.ToString()).Text?
Yes, you can use
Control c = this.Controls.Find("chkCategory" + i.ToString(), true).Single();
(c as textBox).Text = ...;
Add some errorchecking and wrap it in a nice (extension) method.
Edit: It returns Control[] so either a [0] or a .Single() are needed at the end. Added.
for(...)
{
CheckBox c = this.Controls["chkCategory" + i.ToString()] as CheckBox ;
c.Text = categories[i];
}
You can do that with reflection. But don't.
It's more proper to instantiate a list of contols, add them programmatically to your form, and index that.
Sometimes it can help to put your controls into an array or collection as such:
Checkbox[] chkCataegories = new Checkbox[] { chkCategory1, chkCategory2 ... };
for(int i = 0; i < chkCategories.Length; i++)
chkCategories[i].Text = categories[i];
As another approach, you can dynamically create your checkboxes at runtime instead of design time:
for(int i = 0; i < categories.Length; i++)
{
Checkbox chkCategory = new chkCategory { Text = categories[i] };
someContainer.Controls.Add(chkCategory);
}
At least with dynamically created controls, you don't need to modify your GUI or your form code whenever you add new categories.
You don't need dynamic for that. Put chkCategory1 - 12 in an array, and loop through it with a for loop. I would suggest you keep it around in a field and initialize it at form construction time, because chkCategory seems to be related. But if you want a simple example of how to do it in that simple method, then it would be something like this:
private void frmFilter_Load(object sender, EventArgs e)
{
var chkCategories = new [] { chkCategory1, chkCategory2, chkCategory3, .......... };
for(int i = 0 ; i < chkCategories.Length ; i++ )
chkCategoies[i].Text = categories[i];
}
You know more about the application, so you could perhaps avoid writing out all the control names - for instance, if they are placed on a common parent control, then you could find them by going through it's children.
No, but you could do something like this (untested, beware of syntax errors):
private readonly CheckBox[] allMyCheckboxes = new CheckBox[] { chkCategory1, chkCategory2, ... }
Then you just need to do
for (i = 0; i < 12; i++) allMyCheckboxes[i].Text = categories[i];
The "this.Controls["chkCategory" + i.ToString()]" and "this.Controls.Find("chkCategory" + i.ToString(), true)" both do not work... the former informs you that the contents of the [] are not an int and the latter that ControlCollection does not contain a definition for Find.
Use "Control myControl1 = FindControl("TextBox2");" instead.
I needed this form as I was looping through another array, extracting values and using them to populate form fields. Much easier to look for label1, label2, label3, etc.

Categories