I have a WPF Form ,I need to print it ,i use DocumentViewer to print. but when I want to Print it or Preview , I only See the first page while i have more than one page
private void Print(object sender, RoutedEventArgs e)
{
PrintSettings printSettings = PrintSettings.Default;
UIElement container = this.Content as UIElement;
ScrollViewer containerPanel = Helper.FindVisualChildren<ScrollViewer>(container).FirstOrDefault();
var origParentDirection = containerPanel.FlowDirection;
var origDirection = (containerPanel.Content as FrameworkElement).FlowDirection;
if (containerPanel != null && containerPanel.FlowDirection == FlowDirection.RightToLeft)
{
containerPanel.FlowDirection = FlowDirection.LeftToRight;
(containerPanel.Content as FrameworkElement).FlowDirection = FlowDirection.RightToLeft;
}
var window = new Window();
string tempFileName = System.IO.Path.GetTempFileName();
System.IO.File.Delete(tempFileName);
using (XpsDocument xpsDocument = new XpsDocument(tempFileName, FileAccess.ReadWrite, System.IO.Packaging.CompressionOption.Fast))
{
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
(containerPanel.Content as FrameworkElement).Margin = new Thickness(20);
writer.Write((containerPanel.Content as FrameworkElement), printSettings.PrintTicket);
var doc = xpsDocument.GetFixedDocumentSequence();
doc.PrintTicket = printSettings.PrintTicket;
window.FlowDirection = System.Windows.FlowDirection.RightToLeft;
window.Content = new DocumentViewer { Document = doc };
window.Margin = new Thickness(10);
window.ShowDialog();
}
(containerPanel.Content as FrameworkElement).FlowDirection = origDirection;
containerPanel.FlowDirection = origParentDirection;
}
user1780436, I am currently looking for a similar answer. You are trying to print a panel, correct?
I am finding that scaling the element is the biggest problem. Which brings another issue with scaling what you want to print and not the actual visible element. You will have to copy the element to a new element.
public class Copy<T>
{
public static T DeepCopy<T>(T element)
{
string xaml = XamlWriter.Save(element);
StringReader xamlString = new StringReader(xaml);
XmlTextReader xmlTextReader = new XmlTextReader(xamlString);
var DeepCopyobject = (T)XamlReader.Load(xmlTextReader);
return DeepCopyobject;
}
}
or
myNewElement = XamlReader.Parse(XamlWriter.Save(myOldElement.DataContext)) as ElementType
I have found this answer repeatedly on multiple sites to copy/clone an element, but I have had issues with string xaml = XamlWriter.Save(element); causing stackoverflows.
I am currently using.
myNewElement = new ElementType() { DataContext = myOldElement.DataContext }
Either one you use there becomes the issue of changing the size of the Element. This is what I am looking for.
I tried a rendering pass, but that just pointed out that in my situation to use a copied/cloned element. Although while writing this I did get some of it to work, but gives me a black image, note I am trying to scale a Chart.
myNewElement.Width = newWidth;
myNewElement.Height = newHeight;
myNewElement.Measure(new System.Windows.Size(newWidth, newHeight));
myNewElement.Arrange(new Rect(0, 0, newWidth, newHeight));
I tried a layout pass, and didn't get it.
I am going to keep working on mine and I will post anything new I find. Please do the same if you find the answer.
Edit - Here is what I did. My problem and solution
Related
I am trying to save InkCanvas , InkStorkes as a SVG. I found a previous question that works for Wpf,but I have been unable to get it to work with uwp. Wpf InkCanvas save stokes as svg
. I made some changes to it, but I am running into issues with GetGrometry and XamlWriter.
var svg = new SvgDocument();
var colorServer = new SvgColourServer(System.Drawing.Color.Black);
var group = new SvgGroup { Fill = colorServer, Stroke = colorServer };
svg.Children.Add(group);
foreach (var stroke in inkCanvas.InkPresenter.StrokeContainer.GetStrokes())
{
var geometry = stroke.GetGeometry(stroke.DrawingAttributes).GetOutlinedPathGeometry();
var s = XamlWriter.Save(geometry);
if (s.IsNotNullOrEmpty())
{
var element = XElement.Parse(s);
var data = element.Attribute("Figures")?.Value;
if (data.IsNotNullOrEmpty())
{
group.Children.Add(new SvgPath
{
PathData = SvgPathBuilder.Parse(data),
Fill = colorServer,
Stroke = colorServer
});
}
}
}
I implemented an approach from the comments Xavier Xie - MSFT.
The main idea was to use own implementation of ICanvasPathReceiver interface - here is CanvasGeometryToSvgPathReader class:
var svgDocument = new CanvasSvgDocument(canvasDevice);
foreach (var stroke in InkCanvas.InkPresenter.StrokeContainer.GetStrokes())
{
var canvasGeometry = CanvasGeometry.CreateInk(drawingSession, new[] {stroke});
var pathReceiver = new CanvasGeometryToSvgPathReader();
canvasGeometry.SendPathTo(pathReceiver);
var element = svgDocument.Root.CreateAndAppendNamedChildElement("path");
element.SetStringAttribute("d", pathReceiver.Path);
element.SetColorAttribute("fill", stroke.DrawingAttributes.Color);
}
As result ballpoint pen renders fine, highlighter worse and pencil doesn't render.
Full source code: https://github.com/ycherkes/InkToSvg
I'm using the DexExpress.Xpf.Map.v15.1 MapControl and trying to create code that will be able to run in a Windows Service (i.e. no front end) to generate maps as images.
I have the following code which creates a map, adds GeoPoints to a PolyLine and then adds that PolyLine to a map. This works fine in my WPF test harness application:
public MapWindow1()
{
InitializeComponent();
var mapControl = new MapControl
{
Name = "TheMap",
ZoomLevel = 4,
CenterPoint = new GeoPoint(47, 5)
};
var imageLayer = new ImageTilesLayer
{
DataProvider = new OpenStreetMapDataProvider()
};
mapControl.Layers.Add(imageLayer);
var vectorLayer = new VectorLayer();
mapControl.Layers.Add(vectorLayer);
var mapItemStorage = new MapItemStorage();
vectorLayer.Data = mapItemStorage;
var polyLineCollection = DbfGenerator.GeneratePolyLineCollection();
polyLineCollection.ForEach(line =>
{
var mapItem = new MapPolyline();
mapItemStorage.Items.Add(mapItem);
mapItem.Points.AddRange(line);
});
mapControl.MouseDoubleClick += mapControl_MouseDoubleClick;
MainGrid.Children.Add(mapControl);
}
This runs and adds the map control to the WPF page without a problem. I've then added double click handler to export the map as an image:
void mapControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var m = GenerateMapPng((MapControl) sender);
m.Save(#"C:\0Temp\test.bmp");
}
public Bitmap GenerateMapPng(MapControl map)
{
Bitmap bmp;
// export image from map
using (MemoryStream ms = new MemoryStream())
{
var exportOptions = new ImageExportOptions(ImageFormat.Png);
map.ExportToImage(ms, exportOptions);
ms.Position = 0;
bmp = new Bitmap(System.Drawing.Image.FromStream(ms));
}
return bmp;
}
Again - this works without a problem.
However, If I remove the UI element and run the following code:
public MapWindow1()
{
InitializeComponent();
var mapControl = new MapControl
{
Name = "TheMap",
ZoomLevel = 4,
CenterPoint = new GeoPoint(47, 5)
};
var imageLayer = new ImageTilesLayer
{
DataProvider = new OpenStreetMapDataProvider()
};
mapControl.Layers.Add(imageLayer);
var vectorLayer = new VectorLayer();
mapControl.Layers.Add(vectorLayer);
var mapItemStorage = new MapItemStorage();
vectorLayer.Data = mapItemStorage;
var polyLineCollection = DbfGenerator.GeneratePolyLineCollection();
polyLineCollection.ForEach(line =>
{
var mapItem = new MapPolyline();
mapItemStorage.Items.Add(mapItem);
mapItem.Points.AddRange(line);
});
var m = GenerateMapPng(mapControl);
m.Save(#"C:\0Temp\test.bmp");
}
I get a NullReferenceException on the "map.ExportToImage(ms, exportOptions);" line.
I'm assuming that when the WPF application loads it calls a method to initialise the map, but I can't find anything that I can manually do to the control (Load/Init method) to mimic this.
Is there a way to trick the MapControl in to thinking it is in a WPF page when it isn't?
DevExpress said that this was not possible due to the maps reliance on the UI Thread in WPF
I am trying to print an user control. I am passing the user control as framework element in fixed document. When the user control is large it does not get printed fully only one page gets printed and remaining contents are truncated. I am not getting the remaining pages. I need to print fixed document continuously in multiple pages without truncating the content.
public void PrintAllReceipts(object datatoprint, string resourceNameToUserControl)
{
var assembly = Assembly.GetEntryAssembly();
string resourceName = resourceNameToUserControl;
FrameworkElement elem;
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream))
{
elem = XamlReader.Parse(reader.ReadToEnd()) as FrameworkElement;
}
}
var data = datatoprint;
elem.DataContext = data;
//var pageSize = new Size(8.26 * 96, 11.69 * 96); // A4 page, at 96 dpi
//FixedDocument fixedDoc = new FixedDocument();
//PageContent pageContent = new PageContent();
//FixedPage fixedPage = new FixedPage();
//fixedDoc.DocumentPaginator.PageSize = pageSize;
//fixedPage.Width = pageSize.Width;
//fixedPage.Height = pageSize.Height;
//Create first page of document
//fixedPage.Children.Add(elem);
//fixedPage.Measure(pageSize);
//fixedPage.Arrange(new Rect(new Point(), pageSize));
//fixedPage.UpdateLayout();
//((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
//fixedDoc.Pages.Add(pageContent);
PrintDialog dial = new PrintDialog();
PrintContinuous(elem);
//List<FixedDocument > docss = GetFixedDocument(elem, dial);
//foreach (FixedDocument docs in docss)
//{
// dial.PrintDocument(docs.DocumentPaginator, "");
//}
// ShowPrintPreview(docss);
}
public static void PrintContinuous( FrameworkElement fe)
{
PrintDialog pd = new PrintDialog();
bool? result = pd.ShowDialog();
if (!result.HasValue || !result.Value) return;
fe.Dispatcher.Invoke(new Action(() =>
{
fe.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
fe.Arrange(new Rect(fe.DesiredSize));
fe.UpdateLayout();
}), System.Windows.Threading.DispatcherPriority.Render);
pd.PrintVisual(fe, ((String.IsNullOrWhiteSpace
(fe.Name) ? "Temp" : fe.Name) + " PRINT"));
}
You need to paginate the visual.
You could take the control and convert it into a bitmap and then chop the bitmap up into pieces that will fit on a page, add the pages to a FixedDocument and send that to the printer using PrintDialog.PrintDocument.
See this fairly lengthy CodeProject article which fully covers the process and code required: Printing-large-WPF-UserControls
I have the following code to create RadDock programmatically:
public void CreateDock(Control parent)
{
RadDock dock = new RadDock();
DocumentContainer docContainerLeft = new DocumentContainer();
docContainerLeft.SizeInfo.SizeMode = Telerik.WinControls.UI.Docking.SplitPanelSizeMode.Fill;
DocumentTabStrip leftDocStrip = new DocumentTabStrip();
DocumentWindow leftDoc = new DocumentWindow("Left");
leftDocStrip.Controls.Add(leftDoc);
docContainerLeft.Controls.Add(leftDocStrip);
DocumentContainer docContainerRight = new DocumentContainer();
docContainerRight.SizeInfo.SizeMode = Telerik.WinControls.UI.Docking.SplitPanelSizeMode.Fill;
DocumentTabStrip rightDocStrip = new DocumentTabStrip();
DocumentWindow rightDoc = new DocumentWindow("Right");
rightDocStrip.Controls.Add(rightDoc);
docContainerRight.Controls.Add(rightDocStrip);
RadSplitContainer middleSplitter = new RadSplitContainer(Orientation.Vertical);
middleSplitter.Dock = DockStyle.Fill;
middleSplitter.SizeInfo.SizeMode = SplitPanelSizeMode.Fill;
middleSplitter.Controls.Add(docContainerLeft);
middleSplitter.Controls.Add(docContainerRight);
dock.Controls.Add(middleSplitter);
ToolWindow transferWindow = new ToolWindow();
transferWindow.Text = "Transfer Queue";
transferWindow.DockState = DockState.Docked;
dock.DockWindow(transferWindow, DockPosition.Bottom);
dock.Dock = DockStyle.Fill;
parent.Controls.Add(dock);
}
I'm trying to make the middleSplitter to fit the window. However there is always an unwanted area at the bottom. I have a picture of it here but SO does not allow me to post an image.
My question is: How to avoid the unwanted area and make the Splitter fill the window?
The DockWindow method of RadDock might be of help in this case. Here is how you can achieve the desired look:
DocumentWindow middleDoc = new DocumentWindow("Middle");
dock.AddDocument(middleDoc);
DocumentWindow leftDoc = new DocumentWindow("Left");
dock.DockWindow(leftDoc, middleDoc, DockPosition.Top);
DocumentWindow rightDoc = new DocumentWindow("Right");
dock.DockWindow(rightDoc, leftDoc, DockPosition.Right);
ToolWindow transferWindow = new ToolWindow();
transferWindow.Text = "Transfer Queue";
transferWindow.DockState = DockState.Docked;
dock.DockWindow(transferWindow, DockPosition.Bottom);
More information and examples are available in the Telerik UI for WinForms documentation
In MY gtk# Application im trying to show the font selection dialog.Im trying to use the following code,but the FontSelectionDialog constructor need some arguments also does the control execution wait for a font to be selected to set the string font
Can someone guide me?
Gtk.FontSelectionDialog fs = new FontSelectionDialog()
fs.Show ();
font=fs.FontName;
Updated according to additional question
This should help:
FontSelectionDialog dialog = null;
try {
dialog = new FontSelectionDialog("Choose a font");
dialog.Run ();
var name = dialog.FontName;
var pattern = #"^(?<fontName>.*)\s(?<fontSize>\d+(?:\.\d+)?)$";
var regex = new Regex(pattern);
var match = regex.Match(name);
if(match.Success)
{
var fontName = match.Groups["fontName"].Value;
var fontSize = float.Parse(match.Groups["fontSize"].Value);
var font = new System.Drawing.Font(fontName, fontSize);
}
} finally {
if (dialog != null)
dialog.Destroy ();
}