能否在WPF控件中显示System.Drawing.Graphics对象实现打印预览?
在WPF用户控件中复用PrintDocument的Graphics逻辑实现打印预览
直接在WPF用户控件里显示System.Drawing.Graphics对象是不可行的——WPF基于DirectX的绘图系统和System.Drawing(GDI+)属于两套独立的渲染框架,无法直接兼容。但你可以通过将GDI+绘图内容渲染到Bitmap,再转换为WPF支持的ImageSource的方式,完全复用现有打印逻辑实现预览。
具体实现步骤
1. 封装可复用的绘图逻辑
先把PrintPage事件中的绘图代码抽成独立方法,避免重复编写:
// 封装原打印逻辑,接收Graphics对象作为参数 private void DrawReceiptContent(Graphics graphics) { // 以下是你的原有打印代码,直接复用即可 graphics.Clear(Color.White); graphics.DrawString("POS交易收据", new Font("微软雅黑", 14, FontStyle.Bold), Brushes.Black, 10, 10); graphics.DrawLine(Pens.DarkGray, 10, 35, 297, 35); // 80mm宽收据换算为像素(96DPI下≈307px) graphics.DrawString("交易时间:2024-05-20 14:30", new Font("微软雅黑", 10), Brushes.Black, 10, 45); graphics.DrawString("商品:矿泉水 x1 ¥3.00", new Font("微软雅黑", 10), Brushes.Black, 10, 70); // ...其他收据内容绘制 }
2. 生成预览用的ImageSource
创建一个Bitmap,用它的Graphics对象调用封装好的绘图方法,再将Bitmap转换为WPF可识别的ImageSource:
private ImageSource GenerateReceiptPreview() { // 模拟收据尺寸:80mm宽≈307px(96DPI),高度设为足够容纳内容的值 int receiptWidth = 307; int receiptHeight = 600; using (Bitmap previewBitmap = new Bitmap(receiptWidth, receiptHeight)) using (Graphics graphics = Graphics.FromImage(previewBitmap)) { // 调用复用的绘图逻辑 DrawReceiptContent(graphics); // 将Bitmap转换为WPF的BitmapImage using (MemoryStream ms = new MemoryStream()) { previewBitmap.Save(ms, ImageFormat.Png); ms.Position = 0; BitmapImage bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.StreamSource = ms; bitmapImage.EndInit(); bitmapImage.Freeze(); // 冻结对象,允许在UI线程安全使用 return bitmapImage; } } }
3. 在WPF用户控件中显示预览
在用户控件里添加一个Image控件,通过按钮点击或控件加载事件赋值:
// 预览按钮点击事件 private void PreviewBtn_Click(object sender, RoutedEventArgs e) { ReceiptPreviewImage.Source = GenerateReceiptPreview(); }
对应的XAML片段:
<Image x:Name="ReceiptPreviewImage" Stretch="Uniform" Margin="10"/> <Button Content="预览收据" Click="PreviewBtn_Click" Margin="10"/>
注意事项
- DPI适配:
System.Drawing默认使用96DPI,若WPF系统DPI不同,可通过graphics.DpiX = 96; graphics.DpiY = 96;强制对齐,避免预览和打印尺寸偏差。 - 内存管理:所有实现
IDisposable的对象(Bitmap、Graphics、MemoryStream)必须用using包裹,防止内存泄漏。 - 动态高度:若收据内容长度不固定,可先计算内容所需高度(比如通过
Graphics.MeasureString估算文本高度),再创建对应尺寸的Bitmap,避免内容截断或空白过多。
内容的提问来源于stack exchange,提问作者Thanuja Dilhan
相关产品推荐
相关产品推荐

