Print FlowDocument centered on page - wpf

In my WPF application I want to print a custom generated FlowDocument but I have big problems getting the pages on the center of the paper. Every page is aligned to the upper left corner. Even so close the printer can not reach it. Small parts of the document are missing. On the lower and right side there is plenty of empty space so the document can easiely fit on the paper. If it would be centered!
Is the any way to set borders/margin/or offset for the PrintTicket or the Paginator?
I did not find anything that would work.
This is what I do:
// selectedDocument is a FlowDocument
private const double PAGE_HEIGHT = 728;
private const double PAGE_WIDTH = 1024;
var paginator
= ((IDocumentPaginatorSource)this .selectedDocument).DocumentPaginator;
paginator.PageSize = new Size(PAGE_WIDTH, PAGE_HEIGHT);
printDialog.PrintTicket.PageOrientation
= System.Printing.PageOrientation.Landscape;
printDialog.PrintDocument(paginator, "Report");
I also tried different page sizes but it makes no difference.
If I save my FlowDocument as XpsDocument via XpsSerializationManager the created file looks perfect. Borders and margins are all as they should be. In a later step I use this file to create a pdf file. If I then print the pdf-File it looks fine on paper too.

Related

Highlight line(s)/characters in WPF

Scenario
I am currently developing an application. Within this application, I have a TextBox/RichTextBox. I have not decided on the control yet. Within this control, there will be a few paragraphs of text.
Problem
I want to be able to highlight a range of lines, or particular characters within that line, using two given numbers. What would the easiest way to do this be?
Use RichTextBox. You can't use TextBox, that is because TextBox has only one style applied to all text.
Use the TextRange.ApplyPropertyValue method. A TextRange is specified by its starting and ending position, which are two TextPointer.
Something like this
var startingPos = RichTextBox1.ContentStart.GetPositionAtOffset(n1, LogicalDirection.Forward);
var endingPos = startingPos.GetPositionAtOffset(n2 - n1, LogicalDirection.Forward);
var textrange = new TextRange(startingPos, endingPos);
textrange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.DarkRed);
You have to carefully calculate the offsets of the starting and ending positions, taking linebreaks into account.

WPF Visual to XPS document method creates only one page

I have a WPF Window that I want to save to an XPS file (or really, any type of file that would store the window image). This window contains a lengthy DataGrid. So far I am able to write to an XPS file, but the resulting document contains only one page, so most of the DataGrid rows are missing. How can I get the XPSDocumentWriter to use as many pages as necessary?
Here is what I've got so far (I've turned off the grid scroll bar and autosized the window to make sure it is full-sized before writing to XPS file):
Dim visual = CType(Me.Content, Media.Visual)
Me.LogGrid.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden
Me.SizeToContent = Windows.SizeToContent.WidthAndHeight
Dim xd As New System.Windows.Xps.Packaging.XpsDocument(file, IO.FileAccess.ReadWrite)
Dim xw = System.Windows.Xps.Packaging.XpsDocument.CreateXpsDocumentWriter(xd)
xw.Write(visual)
xd.Close()
I think Will's comment is probably the right answer.

Fastest way to convert RTF to FlowDocument

What is the fastest way to convert a RTF to FlowDocument? I store RTF as plain string and then reload it back, I am using following method,
FlowDocument document = new FlowDocument();
document.SetValue(FlowDocument.TextAlignmentProperty, TextAlignment.Left);
TextRange content = new TextRange(document.ContentStart, document.ContentEnd);
if (content.CanLoad(DataFormats.Rtf) && string.IsNullOrEmpty(rtf) == false)
{
// If so then load it with RTF
byte[] valueArray = Encoding.ASCII.GetBytes(rtf);
using (MemoryStream stream = new MemoryStream(valueArray))
{
content.Load(stream, DataFormats.Rtf);
}
}
But this method is very slow. I need to load many RTFs (around 1000). What can be the trick to make the process fast? Is there any other way around to load a Flowdocument?
You really need to define what you actually need. TextBlock is not weak at all.
It has things to offer ;).
Colours(Background/Foreground + you can color specific part of TextBlock even)
Alignments(you can align TextBlocks as you want, and perhaps even part of them?! Not sure about the last one.
It has TextDecorations, which means it supports bold/italic/underline/strikethrough etc.
Fonts(yeah it supports custom fonts and whatever font you want)
But fair enough. I think you should store FlowDocument XAML instead of actual RTF. This way there will be no conversion and it should be multiple times faster. (See DataFormats.xaml)
Hello Vibhore the TextBlock element should be used when limited text support is required, Label can be used when minimal text support is required.
The FlowDocument element is a container for re-flowable documents that support rich presentation of content, and therefore, has a greater performance impact than using the TextBlock or Label controls.

WPF Bitmap performance

I'm trying to understand why my images are not snappy, so I built a sample to test WPF performance. I used a timer to calculate how long my "display images" event handler executed, and used a stop watch to measure how long it took the images to appear on the screen. The bottom line: when displaying 100, 1600, 2500 and 3600 images, WPF took 2, 9, 12 and 16 seconds after my code had finished to display the images on the screen. So I feel helpless: It seems I can't improve my code to make the images appear faster - I need to do something with WPF!
So my question is: What do I need to do differently to make the images display faster?
The test setup is simple:
The window contains a Grid. After the "test" button is clicked, row and column definitions are added.Then an Image is added to each cell of the grid as follows:
var image = new Image();
image.BeginInit();
image.Name = ImageNameFromCell(theRow, theColumn);
image.Stretch = Stretch.None;
image.HorizontalAlignment = HorizontalAlignment.Center;
image.VerticalAlignment = VerticalAlignment.Center;
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.LowQuality);
image.EndInit();
theGrid.Children.Add(image);
Finally, the Source of each image is set to a bitmap:a gray-scale image already scaled down to the estimated screen size. The bitmap is generated as follows:
var smallerBitmapImage = new BitmapImage();
smallerBitmapImage.BeginInit();
smallerBitmapImage.DecodePixelWidth = (int)(theImageWidth);
smallerBitmapImage.UriSource = theUri;
smallerBitmapImage.CacheOption = BitmapCacheOption.None;
smallerBitmapImage.EndInit();
//BitmapFrame bitmapFrame = BitmapFrame.Create(this.FullPath);
var convertedBitmap = new FormatConvertedBitmap();
convertedBitmap.BeginInit();
convertedBitmap.Source = smallerBitmapImage;
convertedBitmap.DestinationFormat = PixelFormats.Gray16;
convertedBitmap.EndInit();
convertedBitmap.Freeze();
So, I'm at my wits end. The images appear with a noticeable delay, and it seems to be out of my control. What can I do?
What appears to have made the difference is setting the image's cache option to OnLoad
smallerBitmapImage.CacheOption = BitmapCacheOption.OnLoad;
This moved the work to my event handler, so now I can use pre-fetching to do this at the background.
Do you actually see all those images at the same time? If not you can use some ItemsControl with a virtualizing panel so only images in view are displayed. (Speaking of panels, your current setup could also be replaced with an ItemsControl which uses a UniformGrid as panel)
You could also try to write a better decoder, which probably is a wasted effort.

Vector graphics in silverlight

I am new to Silverlight. Just created my first application that shows deepzoom images.
Looking for some pointers how to display vector graphics in Silverligth. The graphics are all in 2D and is a series of lines (x1y1, x2y2), points (xy), basic shapes. The data is available in ASCII text files.
What is the way(s) to read the data from files and draw in SL? Do I need to convert / translate the vector objects into images (XAML) first? Where to start?
The ideal case is that all vector obects should be selectable either programmatically or by user actions.
Thanks,
Val
There is no direct drawing API to my knoweldge, but you can add the values seperately by adding various shapes to the visual tree.
The code you are looking for will likely involve the Path class and, in turn, PathFigure and PolyLineSegment (or possibly LineSegment).
Below is some code that draws a square:
PolyLineSegment segment = new PolyLineSegment();
segment.Points.Add(new Point(0, 50));
segment.Points.Add(new Point(50, 50));
segment.Points.Add(new Point(50, 0));
segment.Points.Add(new Point(0, 0));
PathFigure figure = new PathFigure()
{
StartPoint = new Point(0, 0)
};
figure.Segments.Add(segment);
PathGeometry geometry = new PathGeometry()
{
Figures.Add(pathFigure)
};
Path path = new Path()
{
Stroke = new SolidColorBrush(Colors.Black),
StrokeThickness = 2,
Data = pathGeometry
};
// To render, the Path needs to be added to the visual tree
LayoutRoot.Children.Add(path);
Edit If the data in the ASCII text files cannot change at runtime, it might be worth investigating writing a script that transforms the files into XAML so it can be compiled.
First of you have the issue of actually getting access to the files.
Getting the file content
If you have these files held somewhere serverside then you would use WebClient to fetch the file using DownloadStringAsync.
On the other hand if the user is to open a file locally then you need use the OpenFileDialog class to ask them to open the file and then use OpenText on the FileInfo object that OpenFileDialog provides to read the string data.
Parsing
Well its your format so you'll have to code that yourself.
__Generating UI elements_
You will not have to convert it to Xaml. Since you want these vector items to be individually selectable elements then you probably want to use the set of Shape types found in the System.Windows.Shapes namely, Elipse, Line, Path, Polygon, Polyline and Rectangle.
No doubt the format in question has someway to define the position of these elements relative to a fixed 0,0 point. Hence the best panel to use to display these is a Canvas.
You would read through each Vectored item, select create an instance of one of the appropriate shapes set its properties based on the data in the item. You would need to determine its correct location within a Canvas and use the Canvas.Left and Canvas.Top attached properties. The add the shape to the Children collection of the Canvas.

Resources