How to loop through shapes (oval1, oval2, oval3...)? - c#

I've stumbled upon this code to loop through textboxes, and it's what I need, except I need to do it for ovals (Microsoft.VisualBasic.PowerPacks.OvalShape)
for (int i = 1; i < 29; i++)
{
TextBox textBox = (TextBox)Controls["textBox" + i];
}
So it would probably look like
for (int i = 1; i < 29; i++)
{
Shape oval = (Shape)???["oval" + i]
oval.FillColor = blue;
}
I just don't know what the "Controls" counterpart is for shapes. I don't know if this code will work, so please tell me if there's another way to do this.

You can typically use LINQ to select a certain type of control inside of a collection, in this case Controls and ShapeContainer, by using OfType<>.
var ovals = Controls.OfType<ShapeContainer>()
.SelectMany(sc => sc.Controls.OfType<OvalShape>());
foreach (var oval in ovals)
{
oval.FillColor = Color.Blue;
}
As GrawCube pointed out, the ShapeContainer has its own property for accessing its shapes, appropriately named Shapes. You may have to use this instead:
var ovals = Controls.OfType<ShapeContainer>()
.SelectMany(sc => sc.Shapes.OfType<OvalShape>());
Given that some ShapeContainers are inside Panels, and others are not, the query gets a little uglier but not too bad. First we search the main Controls collection, then search all the child Panels, and concatenate the results.
var ovals = Controls.OfType<ShapeContainer>()
.SelectMany(sc => sc.Shapes.OfType<OvalShape>())
.Concat(Controls.OfType<Panel>()
.SelectMany(p => p.Controls.OfType<ShapeContainer>()
.SelectMany(sc => sc.Shapes.OfType<OvalShape>())));

Related

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();

modifying a group of WinForm controls using a loop?

I have a group of textbox controls that i would like to populate with an array of doubles.The controls names are numerically incremented like so
Tol1.Text = lineTolFront[0].ToString();
Tol2.Text = lineTolFront[1].ToString();
Tol3.Text = lineTolFront[2].ToString();
Tol4.Text = lineTolFront[3].ToString();
Tol5.Text = lineTolFront[4].ToString();
Tol6.Text = lineTolFront[5].ToString();
//and so on
is there a simpler way to do this using a loop without having to manually input the values?
First, get all those TextBoxes using LINQ (note: this is useful particularly when you have many controls you do not want manually put in a collection).
var tboxes = this.Controls.Cast<Control>()
.OfType<TextBox>()
.Where(l => l.Name.Contains("Tol"));
and then loop through them and set the content.
int i = 0;
foreach(var tb in tboxes)
tb.Text = lineTolFront[i++].ToString();
You could add the TextBoxes to a collection first. It's a little less copy/paste work at least.
var textBoxes = new List<TextBox> { Tol1, Tol2, Tol3, Tol4, Tol5, Tol6 };
for (var i = 0; i < lineTolFront.Count; i++)
textBoxes[i].Text = lineTolFront[i].ToString();
Regarding M Patel's comment, make sure you add the TextBoxes to the collection in the same order you want to assign the doubles from the lineTolFront array.
You could add your controls to an array and loop through it:
var controls = new[] { Tol1, Tol2, Tol3, Tol4, Tol5, }; //etc
for(int i = 0; i < controls.Length; i++)
{
controls[i].Text = lineTolFront[i].ToString();
}

Convert a PictureBox inside an listBox back into a PictureBox

i have some PictureBoxes in my program with different colors and I want to count, how much boxes there are for one color. So I created a function to count it:
private void cmdCount(object sender, EventArgs e)
{
int counterWhite, counterRed, counterGreen, counterYellow, counterBlue, counterOrange = 0;
if (alreadyAdded == false)
{
lstBox.Items.Add(picA1);
lstBox.Items.Add(picA2);
lstBox.Items.Add(picA3);
//...
alreadyAdded = true;
}
//Log
String value = Convert.ToString(lstBox.Items.Count);
lblLog.Text = "Objects in array: " + value;
for(int i = 0; i < lstBox.Items.Count; i++)
{
if(lstBox.Items[i].BackColor == Color.White)
{
counterWhite += 1;
}
else if...
}
}
I know, that my for-loop will not work that way, but it's the basic idea how I want to do it.
I have put all my PictureBoxes into my list and in the for-loop I want to count them. First it should play as long as the list is long, then every time it goes to the next box and should check the color of it and then add a one to the seperate counters. The problem is that I get errors every time and I have no idea how to read out the values of the BackColors in my list for each item.
Thank you for maybe helping me out :)
You're getting an error because the ListBox.Items collection is an ObjectCollection... it has to be, since it allows you store any object you want in it.
You'll have to cast the object back to a PictureBox before accessing properties on it:
if (((PictureBox)lstBox.Items[i]).BackColor == Color.White)
{
counterWhite += 1;
}
Or you could switch to a foreach loop and cast them all at once (using LINQ):
foreach (var pBox in new lstBox.Items.Cast<PictureBox>())
{
if (pBox.BackColor == Color.White)
{
counterWhite += 1;
}
...
}
Don't use a ListBox control as temporary storage for referencing your PictureBox controls though. You could create a List<PictureBox> to store references in, and then you won't have to cast when you iterate through the collection.
Or better yet (and the one I'd choose), just query the controls on your Form and count the number of controls of type "PictureBox" that have the BackColor you're looking for (using LINQ again).
var counterWhite = Controls.OfType<PictureBox>()
.Count(p => p.BackColor == Color.White);
var counterGreen = Controls.OfType<PictureBox>()
.Count(p => p.BackColor == Color.Green);

Code generation using loop

I am new to C# programming. I have number of text boxes on a form and instead of writing the same code for each text box, is it possible to use loop for writing same code for each text box? In the code below can we use the variable i for the same?
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 3; i++)
{
MessageBox.Show(amountTextBox.Text);
MessageBox.Show(amountTextBox1.Text);
MessageBox.Show(amountTextBox2.Text);
MessageBox.Show(amountTextBox3.Text);
}
}
Thanks in advance.
Instead of trying to generate code (which is a lot harder than it sounds), whenever you have variables named something1, something2, … somethingN, you should consider using an array, or some other collection.
Create an array of text boxes, like this:
var amountTextBoxes = new[] { amountTextBox, amountTextBox1, amountTextBox2, amountTextBox3 };
And then loop through them like this:
for (int i = 0; i < amountTextBoxes.Length; i++)
{
MessageBox.Show(amountTextBoxes[i].Text);
}
Or like this:
foreach (var textBox in amountTextBoxes)
{
MessageBox.Show(textBox.Text);
}
Another option that would probably work in this specific case, (though this solution is not as general as the previous one) involves directly searching for the controls based on the name. If this is a Windows Forms application, you could use Find (assuming all controls have the same name pattern):
for (int i = 0; i < 3; i++)
{
var controlName = "amountTextBoxes" + i;
vat textBox = (TextBox)this.Controls.Find(controlName, true)[0];
MessageBox.Show(textBox.Text);
}
Or if this is WPF, you could use FindName:
for (int i = 0; i < 3; i++)
{
var controlName = "amountTextBoxes" + i;
vat textBox = (TextBox)this.FindName(controlName);
MessageBox.Show(textBox.Text);
}
You can try something like this
foreach (Control x in this.Controls)
{
if (x is TextBox)
{
MessageBox.Show(((TextBox)x).Text);
}
}
Better version with OfType extension method:
foreach (TextBox x in this.Controls.OfType<TextBox>().OrderBy(x => x.Name))
{
MessageBox.Show(x.Text);
}
Here is a linq version.
this.Controls
.OfType<TextBox>()
.ToList()
.ForEach(control =>
MessageBox.Show(control.Text));
Instead of using for loop you can do like this also..
*note * - This is for all the textbox controls in the form.. for specific textboxes you may use a for loop which loop through an array or collection of text boxes you need .
foreach(Control control in this.Controls)
{
if(control.GetType() == typeof(TextBox))
{
MessageBox.Show(control.Text);
}
}
As Selman22 mentioned you can solved it using this.Controls.OfType(). You can further refine your query as mentioned below
foreach (TextBox textBox in this.Controls.OfType<TextBox>().Where(x => x.Name.Contains("amountTextBox")).OrderBy(x => x.Name).ToList())
{
MessageBox.Show(textBox.Text);
}
A simple and maintainable way would be to yield return every textbox you're interested in, in the order that you're interested in, and then iterate over that.
private void button1_Click(object sender, EventArgs e)
{
foreach (var textBox in GetAmountTextBoxes())
MessageBox.Show(textBox.Text);
}
private IEnumerable<TextBox> GetAmountTextBoxes()
{
yield return amountTextBox;
yield return amountTextBox1;
yield return amountTextBox2;
yield return amountTextBox3;
}
If you have many textboxes and maintaining this list is cumbersome, you could generalise it to something like:
return Controls.OfType<TextBox>();
But take care to filter it, if necessary, to only the textbox controls you need with Where.
And if order is important, you'll need to devise some function to sort the textboxes (in conjunction with OrderBy). This is necessary because the default sorting algorithm will sort TextBox10 before TextBox1.
Your Code Rewritten:
for (int i = 0; i < 3; i++)
{
MessageBox.Show(amountTextBox[i].Text);
}

Categories