jimmious
jimmious

Reputation: 368

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 :)

Upvotes: 0

Views: 4892

Answers (1)

nempoBu4
nempoBu4

Reputation: 6621

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: Result

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:
Watermarks

Upvotes: 1

Related Questions