DevExpress XtraReport replace XRPictureBox control on runtime - c#

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:

Related

UISearchBar not resizing on phone rotation

I am having an issue where my UISearchBar does not resize on phone rotation unless I touch on the search bar so that it has focus (see images below).
The search bar is created and added to a UIMapView as a subview. See code.
Searchbar creation:
public UISearchController DefineSearchController()
{
_searchResultsController = new SearchResultsVC(_mapView);
_searchResultsController.searchItemSelected += PlaceSelect;
_searchUpdater = new SearchResultsUpdator();
_searchUpdater.UpdateSearchResults += _searchResultsController.Search;
//add the search controller
var searchController = new UISearchController(_searchResultsController)
{
SearchResultsUpdater = _searchUpdater
};
var scb = searchController.SearchBar;
scb.SizeToFit();
scb.SearchBarStyle = UISearchBarStyle.Minimal;
var img = UIImage.FromBundle("tabSpace");
scb.SetBackgroundImage(img, UIBarPosition.Top, UIBarMetrics.Default);
var textField = scb.ValueForKey(new NSString("searchField")) as UITextField;
if (textField != null)
{
var backgroundView = textField.Subviews[0];
if (backgroundView != null)
{
backgroundView.BackgroundColor = UIColor.White;
backgroundView.Layer.BorderColor = AppColour.PersianBlue.GetUIColour().CGColor;
backgroundView.Layer.BorderWidth = 1;
backgroundView.Layer.CornerRadius = 10;
backgroundView.ClipsToBounds = true;
}
}
var localEnterPoI = NSBundle.MainBundle.LocalizedString("placeHolderSearchForLocation", "Enter a PoI to search for");
scb.Placeholder = localEnterPoI;
searchController.Delegate = new SearchControllerDelegate();
searchController.HidesNavigationBarDuringPresentation = false;
return searchController;
}
Added to the subview:
//Define Search Controller
_mapSearchManager = new MapSearchManager(_mapView);
_searchController = _mapSearchManager.DefineSearchController();
var scb = _searchController.SearchBar;
_mapView.AddSubview(scb);
NSLayoutConstraint.ActivateConstraints(new NSLayoutConstraint[]{
scb.TopAnchor.ConstraintEqualTo(_mapView.TopAnchor, 30),
scb.LeadingAnchor.ConstraintEqualTo(_mapView.LeadingAnchor, 10),
scb.TrailingAnchor.ConstraintEqualTo(_mapView.LeadingAnchor, -10),
});
I heave search extensively and was only able to find one similar issue:
UISearchBar doesn't resize when frame is resized in IOS 11
I implementing both of suggestion but it didn't make any difference.
Has anyone else encounted this or know what a possible solution might be.
Cheers

C# How to Display Image(resource) array in TabPage

Goal: when the application starts I want to generate a button per each picture in my resources (6 for testing, 128 final build), in side of a TabPage.
Here is where i am at so far:
private void tabPage1_load(object sender, EventArgs e)
{
ResourceSet rs = new ResourceSet("");
IDictionaryEnumerator id = rs.GetEnumerator();
List<Bitmap> CIcons = new List<Bitmap>();
while (id.MoveNext())
{
if (id.Value is Bitmap)
CIcons.Add((Bitmap)id.Value);
}
}
this doesn't seem to do the trick, any suggestions would be greatly appreciated
Edit(addition): the issue is when the application starts I'm not seeing the images listed int "tabPage1".
also yes i do have 6 images added to my "Resource Folder" inside Visual Studios.
Just for future folks i wanted to add the finished working code:
// Button list start
// Credit to Jcl
ResourceSet rs = Properties.Resources.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
IDictionaryEnumerator id = rs.GetEnumerator();
List<Bitmap> CIcons = new List<Bitmap>();
while (id.MoveNext())
{
if (id.Value is Bitmap)
CIcons.Add((Bitmap)id.Value);
}
int yposition = 0;
foreach (var bmp in CIcons)
{
Button button = new Button();
button.Location = new Point(0, yposition);
button.Size = new Size(125, 125);
button.Visible = true;
button.BackgroundImage = bmp;
tabPage1.Controls.Add(button);
yposition += 125;
}
//Button list end
If you want to generate a button, I'd say something like:
private void tabPage1_load(object sender, EventArgs e)
{
ResourceSet rs = new ResourceSet("");
IDictionaryEnumerator id = rs.GetEnumerator();
List<Bitmap> CIcons = new List<Bitmap>();
while (id.MoveNext())
{
if (id.Value is Bitmap)
CIcons.Add((Bitmap)id.Value);
}
// Vertical aligned: i'll let you figure out how to position them
int yposition = 0;
foreach(var bmp in CIcons)
{
var button = new Button();
button.Location = new Point(0, yposition);
button.Size = new Size(50, 20); // for example
button.Visible = true;
button.BackgroundImage = bmp;
tabPage1.Controls.Add(button);
yposition += 20; // height of button
}
}
Update
As noted in the comments (I thought it was example code, but seems it's not), you also need to specify where to get the ResourceSet from. In your case, change:
ResourceSet rs = new ResourceSet("");
for
ResourceSet rs = Properties.Resources.ResourceManager.GetResourceSet(
CultureInfo.CurrentUICulture, true, true);
Code legibility bonus
All this code:
IDictionaryEnumerator id = rs.GetEnumerator();
List<Bitmap> CIcons = new List<Bitmap>();
while (id.MoveNext())
{
if (id.Value is Bitmap)
CIcons.Add((Bitmap)id.Value);
}
Is equivalent to:
List<Bitmap> CIcons = new List<Bitmap>();
foreach(var bmp in rs.OfType<Bitmap>())
CIcons.Add(bmp);
And since you can create a list from an enumerable, you could simply do:
List<Bitmap> CIcons = new List<Bitmap>(rs.OfType<Bitmap>());
But also, since you are not using your bitmap list for anything else than creating the buttons, you could just not define it, and then your whole code becomes:
var rs = Properties.Resources.ResourceManager.GetResourceSet(
CultureInfo.CurrentUICulture, true, true);
int yposition = 0;
foreach (var bmp in rs.OfType<Bitmap>())
{
var button = new Button()
{
Location = new Point(0, yposition),
Size = new Size(125, 125),
Visible = true,
BackgroundImage = bmp,
};
tabPage1.Controls.Add(button);
yposition += 125;
}
This could be further optimized: if I was you, instead of positioning by calculating the pixel location of each component, I'd use a FlowLayoutPanel to arrange the buttons. Usage of the FlowLayoutPanel is way outside the scope of this question though, I'm just mentioning it just in case you want to investigate and google further

Print multiple pages of xaml controls

I'm trying to implement a WPF Print function. It's working as long as the user doesnt want to print more than fits to one page. My Application enables the user to create xaml in runtime. Now i want to also enable him to print the xaml controls he created.
I have checked the total height of all xaml controls, devided by the pageheight and ceiled that number, so i know how many pages i have to print.
Next I'm creating a List of FrameworkElements for each page (see logic below) and store every List (each stands for one page) in an array.
At the end i want to create a preview which contains every page and enables the user to print all pages. In order to do that i have to put the pages together to a Document, but i dont know how. Please take a look at my code:
Package package = Package.Open("test.xps", FileMode.Create);
// Create new xps document based on the package opened
XpsDocument doc = new XpsDocument(package);
// Create an instance of XpsDocumentWriter for the document
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
// Write the canvas (as Visual) to the document
double height = element.ActualHeight;
double width = element.ActualWidth;
System.Windows.Controls.PrintDialog printDlg = new System.Windows.Controls.PrintDialog();
Size pageSize = new Size(printDlg.PrintableAreaWidth, printDlg.PrintableAreaHeight);
int pageCount = (int)Math.Ceiling(height / pageSize.Height);
if (pageSize.Height < height) {
var grid = element as Grid;
var children = grid.Children;
List<FrameworkElement>[] pages = new List<FrameworkElement>[pageCount-1];
int i = 0;
double currentHeight = 0;
foreach (FrameworkElement c in children) {
currentHeight += c.RenderSize.Height;
if (currentHeight < pageSize.Height) {
pages[i] = new List<FrameworkElement>();
pages[i].Add(c);
}
else {
i++;
currentHeight = 0;
pages[i] = new List<FrameworkElement>();
pages[i].Add(c);
}
}
for (int j = 0; j < pageCount; j++) {
var collator = writer.CreateVisualsCollator();
collator.BeginBatchWrite();
foreach (FrameworkElement c in pages[j]) {
collator.Write(c);
}
collator.EndBatchWrite();
}
}
doc.Close();
package.Close();
string filename = #"C:\Users\rzimmermann\Documents\Visual Studio 2012\Projects\MvvmLightPrintFunction\MvvmLightPrintFunction\bin\Debug\test.xps";
DocumentViewer viewer = new DocumentViewer();
doc = new XpsDocument(filename, FileAccess.Read);
viewer.Document = doc.GetFixedDocumentSequence();
Window ShowWindow = new Window();
ShowWindow.Width = 400;
ShowWindow.Height = 300;
ShowWindow.Content = viewer;
ShowWindow.Show();
#kenny is right you need to use the FixedPages. For a great tutorial pleas see: http://www.nbdtech.com/Blog/archive/2009/04/20/wpf-printing-part-2-the-fixed-document.aspx
As far as adding pages to a document you can do it like so:
doc.Pages.Add(page1Content);
doc.Pages.Add(page2Content);
//ect.
... PrintDialog dialog = new PrintDialog();
//dialog.PrintVisual(this.scrollCheckCardinfo, "");
Nullable<Boolean> print = dialog.ShowDialog();
if (print == true)
{
Grid DynamicGrid = new Grid();
DynamicGrid.Margin = new Thickness(100, 50, 0, 0);
RowDefinition gridRow1 = new RowDefinition();
gridRow1.Height = new GridLength(45);
RowDefinition gridRow2 = new RowDefinition();
DynamicGrid.RowDefinitions.Add(gridRow1);
DynamicGrid.RowDefinitions.Add(gridRow2);
TextBlock txtBlock1 = new TextBlock();
txtBlock1.Text = "Printed by xyz " + DateTime.Now.ToString();
txtBlock1.FontSize = 14;
txtBlock1.FontWeight = FontWeights.Bold;
txtBlock1.VerticalAlignment = VerticalAlignment.Top;
Grid.SetRow(txtBlock1, 0);
Grid.SetRow(this.scrollCheckCardinfo, 1);
DynamicGrid.Children.Add(txtBlock1);
DynamicGrid.Children.Add(CloneXaml(this.scrollCheckCardinfo));
dialog.PrintVisual(DynamicGrid, "xyz");
}...
public static T CloneXaml<T>(T source)
{
string xaml = XamlWriter.Save(source);
StringReader sr = new StringReader(xaml);
XmlReader xr = XmlReader.Create(sr);
return (T)XamlReader.Load(xr);
}
this.scrollCheckCardinfo is a Grid.

Clicking on image always shows last image in full view Xamarin IOS

In tableview cell I am dynamically showing some messages and images,If i am having more images
showing in horizontal scroll. now what my task is Clicking on particular image need to show that image in full page view, i have done the code, but my problem is clicking on any image showing last image in full view.
Can anyone please help me.
if (contents.Count > 0)
{
_scrollView = new UIScrollView (){Tag = 1002};
//_image = new UIImageView (UIImage.FromBundle("placeholder.png"));
_scrollView.Frame = new RectangleF (0, rowHeight, 320, 300);
_scrollView.PagingEnabled = true;
_scrollView.Bounces = true;
_scrollView.DelaysContentTouches = true;
_scrollView.ShowsHorizontalScrollIndicator = true;
//_scrollView.ScrollRectToVisible (new RectangleF (320, 0, 320, 480), true);
ContentView.Add(_scrollView);
int x = 35;
bool setRowHeight = true;
int scrollwidth = 0;
foreach (var contentItem in contents)
{
if (contentItem.FilePath.Length != 0)
{
index++;
//_image.SetImage (new NSUrl (contentItem.FilePath), UIImage.FromBundle ("placeholder.png"));
//_image.Tag = 1001;
_image = new UIImageView(FromUrl(contentItem.FilePath)) { Tag = 1001 };
_imagePath = contentItem.FilePath;
_image.Frame = new RectangleF(x, 0, 250, _image.Image.CGImage.Height);
x = x + (Convert.ToInt32( Bounds.Width));
scrollwidth = scrollwidth + Convert.ToInt32( Bounds.Width);
_scrollView.ContentSize = new SizeF (scrollwidth,150);
_scrollView.Add (_image);
if (setRowHeight) {
rowHeight += _image.Image.CGImage.Height + 10;
setRowHeight = false;
}
// ================
var doubletap = new UITapGestureRecognizer();
doubletap.NumberOfTapsRequired = 1; // single tap
doubletap.AddTarget(this, new MonoTouch.ObjCRuntime.Selector("DoubleTapSelector"));
_image.AddGestureRecognizer(doubletap); // detect when the scrollView is tapped
_image.UserInteractionEnabled = true;
// =================
}
}
}
[MonoTouch.Foundation.Export("DoubleTapSelector")]
public void OnDoubleTap(UIGestureRecognizer sender)
{
FullImageViewControler fullImageViewController = new FullImageViewControler(_imagePath);
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(fullImageViewController, true, null);
}

MonoTouch - Add UIActionSheet to Top Navigation Bar of my ViewController

I've got the following UIActionSheet.
How do I add it to my top navigation bar?
Preferably as the far right button.
var sheet = new UIActionSheet ("");
sheet.AddButton ("Discard Picture");
sheet.AddButton ("Pick New Picture");
sheet.AddButton ("Cancel");
sheet.CancelButtonIndex = 2;
// Dummy buttons to preserve the space for the UIImageView
for (int i = 0; i < 4; i++) {
sheet.AddButton("");
sheet.Subviews[i+4].Alpha = 0; // And of course it's better to hide them
}
var subView = new UIImageView();
subView.ContentMode = UIViewContentMode.ScaleAspectFill;
subView.Frame = new RectangleF(23,185,275,210);
// Late Steve Jobs loved rounded corners. Let's have some respect for him
subView.Layer.CornerRadius = 10;
subView.Layer.MasksToBounds = true;
subView.Layer.BorderColor = UIColor.Black.CGColor;
sheet.AddSubview(subView);
NavigationController.Add(sheet);
You can show an ActionSheet using the ShowFrom methods.
In particular, ShowFromToolbar shows the sheet from the top toolbar button.
Here's an example which shows the sheet in different ways depending on whether you are on tablet or phone:
void ActionMenu()
{
//_actionSheet = new UIActionSheet("");
UIActionSheet actionSheet = new UIActionSheet (
"Customer Actions",
null,
"Cancel",
"Delete Customer",
new string[] {"Change Customer"});
actionSheet.Style = UIActionSheetStyle.Default;
actionSheet.Clicked += delegate(object sender, UIButtonEventArgs args) {
switch (args.ButtonIndex)
{
case 0: DeleteCustomer(); break;
case 1: ChangeCustomer(); break;
}
};
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone)
actionSheet.ShowFromToolbar(NavigationController.Toolbar);
else
actionSheet.ShowFrom(NavigationItem.RightBarButtonItem, true);
}
https://github.com/slodge/MvvmCross-Tutorials/blob/master/Sample%20-%20CustomerManagement/CustomerManagement/CustomerManagement.Touch/Views/CustomerView.cs#L67

Categories

Resources