populate PictureBox with Images using Foreach loop - c#

In my project I have collection of PictureBoxes and a filled ImageList. I want to populate each pictureBox with the each Image in ImageList using foreach Loop. I know how to do using For loop but I dont know how to do it using foreach loop. I am asking this just for knowledge purpose. I think this can be achieved using Linq inside foreach loop but I am a beginner so I have no Idea how to do it.
I tried the below code in for loop:
for (intimgcount = 0; intimgcount < intMaxPics; intimgcount++)
{
pbxCollection[intimgcount].Image = imglst.Images[intimgcount];
}
the code which I want to use in foreach loop is:
var pbxCollection = new List<PictureBox>(); //PictureBox collection
EDIT: How to set the positions of Picture Box collection in the form?
I tried:
var i = 0;
foreach (var pbx in pbxCollection)
{
pbx.Image = imglst.Images[i++];
//set location:
pbx.Width = 100;
pbx.Height = 100;
pbx.Location = new Point(0, pbx.Height * i);
//add to form:
this.Controls.Add(pbx);
}

You can do it this way.
var pbxCollection = new List<PictureBox>();
foreach (Image img in imglst.Images)
{
PictureBox pb = new PictureBox();
pb.Image = img;
pbxCollection.Add(pb);
}

Use a variable to increment index of collection:
var i = 0;
foreach (var pbx in pbxCollection)
{
pbx.Image = imglst.Images[i++];
//set location:
pbx.Location = new Point(0, pbx.Image.Height * i);
//add to form:
this.Controls.Add(pbx);
}

Related

Grid child is already another visual or the root of a compositionTarget

I want in set all images from list to grid. But I have problem with adding second image in grid with Children.Add.
Here is my example:
List<Image> images = new List<Image>(8);
images.AddRange(Enumerable.Repeat(new Image(), 8));//8 empty images
Then setting images:
foreach (var image in images)
{
BitmapImage b = new BitmapImage();
b.BeginInit();
b.UriSource = new Uri("path");
b.EndInit();
image.Source = b;
image.Width = 50;
image.Height = 50;
}
Then in one function call like this:
private void put_images()
{
int i = 0;
foreach (var image in images)
{
Grid.SetRow(image, i);
Grid.SetColumn(image, i);
LayoutRoot.Children.Add(image);//here is error
i++;
}
}
I got runtime error: Additional information: Specified Visual is already a child of another Visual or the root of a CompositionTarget.
I don't understand why, because I got 8 different images, and I don't know how to fix that problem.
The problem is the code where you create the images.
images.AddRange(Enumerable.Repeat(new Image(), 8));
This is one image object, with 8 references in the collection.
The documentation of Enumerable.Repeat says:
element
Type: TResult
The value to be repeated.
The value of new Image() is the reference to that Image.
Which means you have 8 references to the same object in the collection.
You can easily verify that by comparing the first with the second entry in the list.
images[0] == images[1] //=true
A solution would be to use a for loop to instantiate the images.
for(int i = 0; i < 8; i++) images.Add(new Image());
It's seems the problem is the creating images.
Now I don't create 8 empty images, but I create Image, and then add in list. Now it's work:
for(int i = 0; i < 8; i++)
{
Image a = new Image();
BitmapImage b = new BitmapImage();
b.BeginInit();
b.UriSource = new Uri("path");
b.EndInit();
a.Source = b;
a.Width = 50;
a.Height = 50;
images.Add(a);
}

DevExpress XtraReport replace XRPictureBox control on runtime

So in our Report we have an ImageBox in the Detail Band which we want to have a different image per page.
Seeing that changing it in the BeforePrint Event of the Detail Band doesn't work (since it's only called once per print of the Report) I followed the following approach so far (which doesn't work):
In the PrintOnPage Event of a label of the Page Header Band of the Report (in order to have it called per page and be able to use the PrintOnPageEventArgs in the new XRPictureBox - I need the PageIndex):
private void xrLabel10_PrintOnPage(object sender, PrintOnPageEventArgs e)
{
this.Detail.Controls.Remove(xrPictureBox1); //Existing PictureBox control
this.Detail.Controls.Add(PictureBox(e));
}
Which calls this:
private List<Bitmap> _imageList;
public XRPictureBox PictureBox(PrintOnPageEventArgs e)
{
XRPictureBox pictureBox = new XRPictureBox();
var articleService = DependencyResolver.Current.GetService<IArticleService>();
int width;
int height;
pictureBox.Name = "xrPictureBox_" + e.PageIndex;
pictureBox.BackColor = Color.Transparent;
pictureBox.Dpi = 254F;
pictureBox.LocationFloat = new DevExpress.Utils.PointFloat(108.4792F, 71.4375F);
pictureBox.Name = "xrPictureBox_" + e.PageIndex;
pictureBox.SizeF = new SizeF(950F, 1225F);
pictureBox.Sizing = ImageSizeMode.Squeeze;
pictureBox.StylePriority.UseBackColor = false;
if (ReportUnit == ReportUnit.HundredthsOfAnInch)
{
width = (int)(GraphicsUnitConverter.Convert(xrPictureBox1.Size.Width, GraphicsUnit.Inch, GraphicsUnit.Pixel) / 100);
height = (int)(GraphicsUnitConverter.Convert(xrPictureBox1.Size.Height, GraphicsUnit.Inch, GraphicsUnit.Pixel) / 100);
}
else
{
width = (int)(GraphicsUnitConverter.Convert(xrPictureBox1.Size.Width, GraphicsUnit.Millimeter, GraphicsUnit.Pixel) / 10);
height = (int)(GraphicsUnitConverter.Convert(xrPictureBox1.Size.Height, GraphicsUnit.Millimeter, GraphicsUnit.Pixel) / 10);
}
if (_imageList == null)
{
_imageList = articleService .GetListOfImages((int)articleId.Value, width, height, PageColor); //this gets a List<Bitmap>
}
if (_imageList[e.PageIndex] == null)
return null;
pictureBox.Image = _imageList[e.PageIndex];
return pictureBox;
}
So basically my idea was to replace the existing Control with a new XRPictureBox with the new image. But it just doesn't appear in the Report, even though while debugging I see the code being run and retrieving the correct images for the correct pages.
Edit: nempoBu4's answer is correct generally, but unfortunately I failed to clarify an additional issue which makes it not perfect for my situation:
The report also has a subreport right next to the PictureBox and this subreport can expand to more than one pages. We wanted the PictureBox to render a different image in each of these pages and they don't trigger the PrintOnPage event of the PictureBox. I will add an answer with the workaround we found as soon as I can :)
PictureBox
You can use the PrintOnPage event of your PictureBox itself.
Here is example:
var source = new List<Tuple<int, string>>();
for (int index = 0; index < 100; index++)
source.Add(new Tuple<int, string>(index, "Name" + index));
var pictureBox = new XRPictureBox();
pictureBox.PrintOnPage += (sender, e) =>
{
if (_imageList[e.PageIndex] == null)
return;
pictureBox.Image = _imageList[e.PageIndex];
};
var labelItem1 = new XRLabel();
labelItem1.DataBindings.Add("Text", null, "Item1");
labelItem1.LeftF = 100;
var labelItem2 = new XRLabel();
labelItem2.DataBindings.Add("Text", null, "Item2");
labelItem2.LeftF = 200;
var detail = new DetailBand();
detail.Controls.AddRange(new XRControl[] { pictureBox, labelItem1, labelItem2 });
var report = new XtraReport();
report.Bands.Add(detail);
report.DataSource = source;
report.ShowRibbonPreview();
The result of example:
Watermarks
If you want to have only one image per page then you can use watermarks.
Here is example:
var source = new List<Tuple<int, string>>();
for (int index = 0; index < 100; index++)
source.Add(new Tuple<int, string>(index, "Name" + index));
var labelItem1 = new XRLabel();
labelItem1.DataBindings.Add("Text", null, "Item1");
labelItem1.LeftF = 100;
var labelItem2 = new XRLabel();
labelItem2.DataBindings.Add("Text", null, "Item2");
labelItem2.LeftF = 200;
var detail = new DetailBand();
detail.Controls.AddRange(new XRControl[] { labelItem1, labelItem2 });
var report = new XtraReport();
report.Bands.Add(detail);
report.DataSource = source;
report.CreateDocument();
foreach (Page page in report.Pages)
if (_imageList[page.Index] != null)
{
var watermark = new Watermark();
watermark.Image = _imageList[page.Index];
page.AssignWatermark(watermark);
}
report.ShowRibbonPreview();
Here is result:

Remove the Labels after draw them dynamically

I am drawing set of Labels dynamically and i want to remove them. I am using the same button to remove and add new Labels. The labels are drawn randomly with random coordinates. But, when i am pressing the button the old Labels should me removed and the new Labels appeared. But, what I am having is that the new labels appears and old Labels appears but empty labels. I want them to be remove at all. See the picture:
//Global Intialization
int xCoor;
int yCoor;
//send the random method
Random coor = new Random();
private void btnRun_Click(object sender, EventArgs e)
{
//Removing the Labels after drawing them in the picBox
this.RemoveOldLabels();
//to draw the Labels rendomely.
for (int x = 1; x <= 25; x++)
{
for (int i = 0; i < 1; i++)
{
//Get the Coordinates for X,Y
xCoor = coor.Next(0, 750);
yCoor = coor.Next(0, 500);
//Start Greating the Labels
Label nodeLabel1 = new Label();
nodeLabel1.Text = x + " : " + xCoor + "," + yCoor;
nodeLabel1.AutoSize = true;
nodeLabel1.Location = new Point(xCoor + 10, yCoor + 5);
nodeLabel1.ForeColor = System.Drawing.Color.Red;
nodeLabel1.BackColor = Color.LightBlue;
//Draw the Labels in the PicBox
this.picNodes.Controls.Add(nodeLabel1);
}
}
}
//this to remove the Labels
private void RemoveOldLabels()
{
List<Label> LabelsToRemove = new List<Label>();
foreach (var x in this.picNodes.Controls)
{
if (x.GetType() == typeof(System.Windows.Forms.Label))
{
LabelsToRemove.Add((Label)x);
}
}
It looks like RemoveOldLabels() is finding the labels, but not actually removing them.
Try getting all "Label" controls, then disposing of them (which should also remove them from the collection and make them disappear off the form).
foreach (var label in picNodes.Controls.OfType<Label>().ToList())
label.Dispose();
Your remove old labels logic does not do anything. It simply adds the labels to a list and that's it.
You need to remove those controls from picNodes as below:
private void RemoveOldLabels()
{
List<Label> LabelsToRemove = new List<Label>();
foreach (var x in this.picNodes.Controls)
{
if (x.GetType() == typeof(System.Windows.Forms.Label))
{
LabelsToRemove.Add((Label)x);
}
}
foreach (var label in LabelsToRemove)
{
this.picNodes.Controls.Remove(label);
label.Dispose();
}
}

Set multiple images to multiple PictureBoxs

what I intend to do is
PictureBox1.Image = ImageHere
But I am not sure how I would go about this on mass other than then
PictureBox2.Image = ImageHere2
PictureBox3.Image = ImageHere3
PictureBox4.Image = ImageHere4
If I could just do [increment] or something but that gets rejected
If you were to put the picture boxes and the images into arrays or the likes of it, you could loop like this:
PictureBox[] pictureBoxes = { PictureBox1, PictureBox2, PictureBox3, PictureBox4 };
Image[] images = { ImageHere1, ImageHere2, ImageHere3, ImageHere4 };
for (int i = 0; i < pictureBoxes.Length; i++)
{
pictureBoxes[i].Image = images[i];
}
There's still the hassle of creating the arrays though.
You can dynamically create your pictureboxes and assign them corresponding values.
Create a list of images and use foreach iterator:
List<Image> images = //get your list of images
foreach(var img in images)
{
PictureBox pb = new PictureBox();
pb.Image = img;
YourControl.Add(pb);
}

cycled pictureboxes

I need to work with much pictureboxes in one cycle. How can i do this? I tryed this :
for (int i = 1; i <= 10; i++)
{
PictureBox[] pb = new PictureBox[i];
pb[i].Image = global::Ippodrom.Properties.Resources.horse;
}
But it crashes with:
An unhandled exception of type 'System.IndexOutOfRangeException' occurred in Ippodrom.exe
Additional information: Index was outside the bounds of the array.
What shall I do?
UPD: I need to change the picture in created picturebox, not to create a new picturebox.
You need to loop through your existing pictureboxes on your form.
This procedure assumes you have the pictureboxes on the form and not in another container, like a panel. If so, adjust this code accordingly:
foreach (PictureBox pb in this.Controls.OfType<PictureBox>()) {
pb.Image = global::Ippodrom.Properties.Resources.horse;
}
What you want is to create an array of 10 PictureBox and initialize each of them.
What you have done is to create 10 arrays, each of size N, where N is [1..10].
Start by creating an array:
PictureBox[] pb = new PictureBox[10];
Now you have an array of 10 PixtureBox references. Each of them holds the value 'null'.
for (int i = 0; i < 10; i++) // C# arrays are zero-indexed, not one
{
// Create a new PictureBox and assign it to the array
pb[i] = new PictureBox();
// Assign an image to this new PictureBox
pb[i].Image = global::Ippodrom.Properties.Resources.horse;
}
The IndexOutOfRangeException occurs because you used a one-based index instead of zero, but the code was flawed to begin with, so it's not relevant.
If you create the Array of PictureBox you don't create any instances. You only declare "space" to hold the References to the Instances.
I guess what you're trying to do is this (but I might be wrong)
PictureBox[] pb = new PictureBox[10]; // creates space for 10 elements, first one is 0
for(int i = 0; i < 10; i++) { // from 0..9
pb[i] = new PictureBox(); // we create the actual thing
pb[i].Image = global::Ippodrom.Properties.Resources.horse;
}
It's probably a lot easier to use a List here
IList<PictureBox> pb = new List<PictureBox>();
for(int i = 0; i < 10; i++) { // if you want exactly 10
var theBox = new PictureBox();
theBox.Image = global::Ippodrom.Properties.Resources.horse;
pb.add(theBox);
}
if you want to change them
IList<PictureBox> pb = new List<PictureBox>() { pictureBox1 /* etc */ };
foreach(PictureBox p in pb) {
p.Image = global::Ippodrom.Properties.Resources.horse;
}
If you want every Picturebox in the Control go with the by LarsTech :)

Categories

Resources