Convert Wpf (Xaml) Control to Xps Document

Convert WPF (XAML) Control to XPS Document

Actually after messing around with heaps of different samples, all of which are incredibly convoluted and require the use of Document Writers, Containers, Print Queues and Print Tickets, I found Eric Sinks article about Printing in WPF

The simplified code is a mere 10 lines long

public void CreateMyWPFControlReport(MyWPFControlDataSource usefulData)
{
//Set up the WPF Control to be printed
MyWPFControl controlToPrint;
controlToPrint = new MyWPFControl();
controlToPrint.DataContext = usefulData;

FixedDocument fixedDoc = new FixedDocument();
PageContent pageContent = new PageContent();
FixedPage fixedPage = new FixedPage();

//Create first page of document
fixedPage.Children.Add(controlToPrint);
((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
//Create any other required pages here

//View the document
documentViewer1.Document = fixedDoc;
}

My sample is fairly simplistic, it doesn't include Page Sizing and Orientation which contains a whole different set of issues that don't work as you would expect.
Nor does it contain any save functionality as MS seem to have forgotten to include a Save button with the Document Viewer.

Save Functionality is relatively simple (and is also from Eric Sinks article)

public void SaveCurrentDocument()
{
// Configure save file dialog box
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "MyReport"; // Default file name
dlg.DefaultExt = ".xps"; // Default file extension
dlg.Filter = "XPS Documents (.xps)|*.xps"; // Filter files by extension

// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();

// Process save file dialog box results
if (result == true)
{
// Save document
string filename = dlg.FileName;

FixedDocument doc = (FixedDocument)documentViewer1.Document;
XpsDocument xpsd = new XpsDocument(filename, FileAccess.ReadWrite);
System.Windows.Xps.XpsDocumentWriter xw = XpsDocument.CreateXpsDocumentWriter(xpsd);
xw.Write(doc);
xpsd.Close();
}
}

So the answer is Yes, you can take an Existing WPF (XAML) Control, databind it and turn it into an XPS document - and its not all that difficult.

Converting Word Document to XPS Document in C# WPF

I wrote an static method that do what you need.

static void SearchDocuments(string directoryPath)
{
try
{
foreach (string fullName in System.IO.Directory.GetFiles(directoryPath,"*.docx")) // if your word documents come from an older version of word, they might have .doc extenstion
{
convertWordToXps(System.IO.Path.GetDirectoryName(fullFileName), System.IO.Path.GetFileNameWithoutExtension(fullFileName));
}
foreach (string nestedDirectory in System.IO.Directory.GetDirectories(directoryPath))
{
SearchDocuments(nestedDirectory);
}
}
catch (System.Exception error)
{
//Do whatever u want on exception
}
}

Btw. think over if you have reason to use static functions.

Print documents via Wpf-controls and convert to XPS

I'm skipping your second question as it is complex enough to be a standalone.

I faced the same issue, but it may be caused by a couple of different things.

If the issue is because the bindings haven't been "tripped" yet, the solution is slightly hacky but is easy to do if you control the DataContext type. You just add a public or internal method to your type that allows you to fire off PropertyChanged events for each public property. Here's an example:

public interface IForceBinding : INotifyPropertyChanged
{
void ForceBindings();
}

public class MyDataContext : IForceBinding
{
public event PropertyChanged;
private string _text;
public string Text
{
get{return _text;}
set{_text = value; OnPropertyChanged("Text");}
}
public void ForceBindings()
{
OnPropertyChanged("Text");
}

private void OnPropertyChanged(string propertyName)
{
// you know the drill
}
}

then, you can use it thusly:

public void Print(MyDataContext preconfiguredContext){
var page = new MyWpfPage();
page.DataContext = preconfiguredContext;
preconfiguredContext.ForceBindings();
// write to xps

If that isn't working, you might be encountering a bug where the bindings on the first page never show up. I'd have to dig for awhile before I can re-find the solution to that.

How to adjust path of XPS document for wpf Application to work on another PC?

You should get the base directory for your running application which you can append to the relative path to the XPS file. This should work even if you deploy the application as long as you have the XPS file in an Assets folder next to the executable.

string xpsFilePath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
@"Assets\Dokhna - Problems - Report.xps");

XpsDocument myDoc = new XpsDocument(xpsFilePath, FileAccess.Read);

How to create XPS file silently?

You can write any UI element directly to an XPS document without using the "print" functionality. Use the XpsDocument and XpsDocumentWriter classes as dictated here.

How to serialize multiple xaml elements into single xps file and print WPF Application c#

Finally lots of digging later found out a solution.

In WPF Application, we can serialize multiple xaml elements individually. All the serialized xaml elements will be in .xps format. Then we can collect back all .xps file and form a single .xps file. This way, we can serialize multiple xaml elements. Thanks.

Center a Control when converting to XPS

So basically the FixedPage was responsible for all my troubles.
It always resized my control to an area larger than the area available from my PrintDialog.
I was under the impression that it was necessary to print a any UI element, since every solution I found online uses it, but I found out I can simply print my control directly.

I had to resize the control a little before printing, but once I removed the FixedPage, this was fairly easy.

      control.UpdateLayout();

control.Width = PrintableSize.Width;
control.Height = PrintableSize.Height;

string tempFilename = fileName + "_temp.xps";

XpsDocument xpsDoc = new XpsDocument(tempFilename, FileAccess.Write);
XpsDocumentWriter xWriter = XpsDocument.CreateXpsDocumentWriter(xpsDoc);
xWriter.Write(control);
xpsDoc.Close();


Related Topics



Leave a reply



Submit