WPF中ScrollViewer滚动后打印完整POS小票的方法
WPF POS小票打印滚动后仅打印可见区域的解决办法
问题根因
WPF的ScrollViewer会对超出可视范围的内容做虚拟化或暂不渲染处理,默认打印方式(直接打印ScrollViewer的Visual)只会捕获当前显示的可见部分,所以滚动后打印就只出可见区域。
解决思路
要么临时让ScrollViewer展开显示全部内容,打印后恢复状态;要么直接针对内容容器进行打印,绕开ScrollViewer的可视限制。
具体实现方案
方案1:临时展开ScrollViewer打印
先保存ScrollViewer的滚动位置和尺寸,临时把它的高度设为内容的实际高度,让所有内容都渲染出来,打印完成后再恢复原样。
修改后的C#打印代码
private void PrintButton_Click(object sender, RoutedEventArgs e) { // 替换成你自己的ScrollViewer和内容容器名称 var scrollViewer = printScrollViewer; var contentContainer = printContent; // 保存原始状态 var originalScrollPos = scrollViewer.VerticalOffset; var originalScrollHeight = scrollViewer.Height; try { // 临时展开ScrollViewer,显示全部内容 scrollViewer.Height = contentContainer.ActualHeight; scrollViewer.UpdateLayout(); // 强制刷新布局,确保内容全渲染 var printDialog = new PrintDialog(); if (printDialog.ShowDialog() == true) { // 打印内容容器,而非ScrollViewer本身 printDialog.PrintVisual(contentContainer, "POS小票"); } } finally { // 恢复ScrollViewer的原始状态 scrollViewer.Height = originalScrollHeight; scrollViewer.ScrollToVerticalOffset(originalScrollPos); scrollViewer.UpdateLayout(); } }
方案2:用FlowDocument打印(更适合动态内容)
如果小票内容是动态生成的,可以把内容转成FlowDocument,用文档分页器打印,完全不受ScrollViewer影响。
示例代码
private void PrintButton_Click(object sender, RoutedEventArgs e) { var printDialog = new PrintDialog(); if (printDialog.ShowDialog() != true) return; // 创建空的FlowDocument var printDoc = new FlowDocument(); var contentPanel = printContent as StackPanel; // 把小票内容逐控件转成FlowDocument的元素 foreach (var child in contentPanel.Children) { if (child is TextBlock tb) { var para = new Paragraph(new Run(tb.Text)); para.FontFamily = tb.FontFamily; para.FontSize = tb.FontSize; para.Margin = tb.Margin; printDoc.Blocks.Add(para); } // 其他控件(如Border、Image)可按需转换 } // 适配小票打印尺寸 printDoc.PageWidth = printDialog.PrintableAreaWidth; printDoc.PageHeight = printDialog.PrintableAreaHeight; printDialog.PrintDocument(((IDocumentPaginatorSource)printDoc).DocumentPaginator, "POS小票"); }
XAML配置注意
确保内容容器(比如StackPanel)不设置固定高度,让它随内容自动扩展:
<ScrollViewer x:Name="printScrollViewer" VerticalScrollBarVisibility="Auto"> <StackPanel x:Name="printContent" Width="280"> <!-- 这里放小票的具体内容:订单号、商品列表、总计等 --> </StackPanel> </ScrollViewer>
核心提醒
- 绝对不要直接打印ScrollViewer,要打印它内部的内容容器,避免只捕获可见区域。
- 打印前必须调用
UpdateLayout(),强制WPF渲染全部内容。 - 打印后一定要恢复ScrollViewer的原始状态,不影响用户后续操作。
内容的提问来源于stack exchange,提问作者Zoraiz
相关产品推荐
相关产品推荐

