首先,我想指出,我已經提出這是微軟的一個錯誤,但他們不願意在這個時候修正它。我正在尋找的是解決方案或更好的方式來實現我所要做的事情,因爲我們的客戶認爲這是一個相當重要的問題。在XPS文件中打印的重複圖像
代碼
MainWindow.xaml
<Grid x:Name="mainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Images}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Print to file" Grid.Row="1" Click="PrintToFile_Click"/>
<Button Content="Print to device" Grid.Row="2" Click="PrintToDevice_Click"/>
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public IList<byte[]> Images { get; set; }
public MainWindow()
{
InitializeComponent();
Assembly currentAssembly = Assembly.GetExecutingAssembly();
this.Images = new List<byte[]>
{
ReadToEnd(currentAssembly.GetManifestResourceStream("PrintingInvestigation.Images.Chrysanthemum.jpg")),
ReadToEnd(currentAssembly.GetManifestResourceStream("PrintingInvestigation.Images.Desert.jpg")),
ReadToEnd(currentAssembly.GetManifestResourceStream("PrintingInvestigation.Images.Hydrangeas.jpg")),
};
this.DataContext = this;
}
public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = 0;
if (stream.CanSeek)
{
originalPosition = stream.Position;
stream.Position = 0;
}
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
if (stream.CanSeek)
{
stream.Position = originalPosition;
}
}
}
private void PrintToDevice_Click(object sender, RoutedEventArgs e)
{
PrintDialog dialog = new PrintDialog();
if (dialog.ShowDialog() == true)
{
Thickness pageMargins;
if (dialog.PrintTicket.PageBorderless.HasValue == true)
{
if (dialog.PrintTicket.PageBorderless.Value == PageBorderless.Borderless)
{
pageMargins = new Thickness(0, 0, 0, 0);
}
else
{
pageMargins = new Thickness(20, 20, 20, 20);
}
}
else
{
pageMargins = new Thickness(20, 20, 20, 20);
}
int dpiX = 300;
int dpiY = 300;
if (dialog.PrintTicket.PageResolution != null &&
dialog.PrintTicket.PageResolution.X.HasValue &&
dialog.PrintTicket.PageResolution.Y.HasValue)
{
dpiX = dialog.PrintTicket.PageResolution.X.Value;
dpiY = dialog.PrintTicket.PageResolution.Y.Value;
}
else
{
dialog.PrintTicket.PageResolution = new PageResolution(dpiX, dpiY);
}
VisualDocumentPaginator paginator = new VisualDocumentPaginator(this.mainGrid, this.mainGrid.ActualWidth);
paginator.PageSize = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight);
dialog.PrintDocument(paginator, "My first print");
GC.Collect();
}
}
private void PrintToFile_Click(object sender, RoutedEventArgs e)
{
string filePath = this.PrintToFile(null, this.mainGrid, "My first print", this.mainGrid.ActualHeight, this.mainGrid.ActualWidth);
Process.Start(filePath);
}
public string PrintToFile(Visual titleVisual, Visual contentVisual, string title, double bottomMost, double rightMost)
{
string printedFilePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), string.Format(CultureInfo.InvariantCulture, "{0}.xps", title));
XpsDocument printedDocument = new XpsDocument(printedFilePath, FileAccess.Write, System.IO.Packaging.CompressionOption.SuperFast);
VisualDocumentPaginator paginator = new VisualDocumentPaginator(contentVisual as FrameworkElement, rightMost);
paginator.PageSize = new Size(793.7, 1122.5);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(printedDocument);
writer.Write(paginator, new PrintTicket
{
Collation = Collation.Collated,
CopyCount = 1,
DeviceFontSubstitution = DeviceFontSubstitution.On,
Duplexing = Duplexing.OneSided,
InputBin = InputBin.AutoSelect,
OutputColor = OutputColor.Color,
OutputQuality = OutputQuality.High,
PageMediaSize = new PageMediaSize(PageMediaSizeName.ISOA4),
PageOrientation = PageOrientation.Portrait,
PageResolution = new PageResolution(PageQualitativeResolution.High),
PagesPerSheet = 1,
TrueTypeFontMode = TrueTypeFontMode.Automatic
});
printedDocument.Close();
return printedFilePath;
}
}
VisualDocumentPaginator.cs
public class VisualDocumentPaginator : DocumentPaginator
{
#region Fields
private double desiredWidth;
private FrameworkElement element;
#endregion
#region Properties
public int Columns
{
get
{
return 1;// (int)Math.Ceiling(Element.ActualWidth/PageSize.Width);
}
}
public int Rows
{
get
{
return (int)Math.Ceiling(element.ActualHeight/PageSize.Height);
}
}
#endregion
#region Constructors
public VisualDocumentPaginator(FrameworkElement element, double desiredWidth)
{
this.desiredWidth = desiredWidth;
this.element = element;
}
#endregion
#region DocumentPaginator Members
public override DocumentPage GetPage(int pageNumber)
{
TransformGroup transforms = new TransformGroup();
double scaleRatio = this.PageSize.Width/this.desiredWidth;
int row = (pageNumber/Columns);
double pageHeight = -PageSize.Height * row/scaleRatio;
double pageWidth = -PageSize.Width * (pageNumber % Columns);
transforms.Children.Add(new TranslateTransform(pageWidth, pageHeight));
// Make sure the control is stretched to fit the page size.
if (scaleRatio != double.NaN)
{
ScaleTransform st = new ScaleTransform(scaleRatio, scaleRatio);
transforms.Children.Add(st);
}
element.RenderTransform = transforms;
Size elementSize = new Size(this.desiredWidth, element.ActualHeight);
element.Measure(elementSize);
element.Arrange(new Rect(new Point(0, 0), elementSize));
var page = new DocumentPage(element, this.PageSize, new Rect(), new Rect());
element.RenderTransform = null;
return page;
}
public override bool IsPageCountValid
{
get { return true; }
}
public override int PageCount
{
get
{
return Columns * Rows;
}
}
public override Size PageSize { set; get; }
public override IDocumentPaginatorSource Source
{
get { return null; }
}
#endregion
}
抱歉發佈所有的代碼,但它涵蓋了所有我看到問題的領域。如果這裏有幫助的是Microsoft bug report,它附有一個示例項目,其中可以複製問題。
問題
問題寫入,其中僅所述第一圖像被打印3次的XPS文件時,如果點擊了「打印到設備」按鈕時,則正確的圖像被打印僅出現。
我綁定到byte []的原因是因爲我在本地SQL CE數據庫中保存了我的圖像。我們將它們存儲在一個數據庫中,因爲它們只有很小的~2KB,並且我們允許用戶將自己的圖標導入到系統中以供使用,並且我們希望有一種機制來保證它們不會被意外刪除。
注意
我注意到,如果我不綁定到字節[]上面提到的話,我看不出問題。鑑於系統目前的工作方式是將圖像存儲在數據庫中,如果有解決方法,我寧願堅持使用它,但我並不完全反對替換這些圖像的存儲機制。
感謝您的支持。我希望能夠找到解決問題的相當快速的解決方案,但客戶現在已決定放棄XPS支持並轉向PDF,因此我認爲我們將重寫我們使用的打印邏輯。我一定會考慮System.Drawing.Printing。 – Bijington