【发布时间】:2015-12-11 15:21:12
【问题描述】:
我正在制作一个用于打印标签的 WPF 应用程序。我想将标签模板设计为 WPF 窗口。在另一个类中,我将实例化这个“窗口模板”,在运行时填充属性并打印标签。我无法在打印前在屏幕上显示标签,因此我无法在此窗口实例上调用 .ShowDialog()。这稍后会发挥作用。
过去一周我一直在研究这个问题,我发现了两种几乎可以分别做我想做的事情的方法,如果我可以将它们结合起来,它会起作用,但我错过了一块。
我可以让它工作,但按照这里的步骤 Printing in WPF Part 2
这完成了打印文档的基本操作。但是,我将无法使用我的模板,我必须将所有内容都放在后面的代码中。这是一个可行的选择,但我想更多地探索模板的想法。
PrintDialog pd = new PrintDialog();
FixedDocument document = new FixedDocument();
document.DocumentPaginator.PageSize = new System.Windows.Size(pd.PrintableAreaWidth, pd.PrintableAreaHeight);
FixedPage page1 = new FixedPage();
page1.Width = document.DocumentPaginator.PageSize.Width;
page1.Height = document.DocumentPaginator.PageSize.Height;
// add some text to the page
Label _lblBarcode = new Label();
_lblBarcode.Content = BarcodeConverter128.StringToBarcode(palletID);
_lblBarcode.FontFamily = new System.Windows.Media.FontFamily("Code 128");
_lblBarcode.FontSize = 40;
_lblBarcode.Margin = new Thickness(96);
page1.Children.Add(_lblBarcode);
// add the page to the document
PageContent page1Content = new PageContent();
((IAddChild)page1Content).AddChild(page1);
document.Pages.Add(page1Content);
pd.PrintQueue = new System.Printing.PrintQueue(new System.Printing.PrintServer(), "CutePDF Writer");
pd.PrintDocument(document.DocumentPaginator, "PalletID");
我只是在这里展示我是如何打印条形码的。在实际程序中,我会在标签上添加所有内容并定位它。
在这个类中,我实例化了我的标签,填充了它的属性,并尝试将它添加到 FixedPage 的 Children - 但它返回了这个错误。
Specified element is already the logical child of another element. Disconnect it first.
为了解决这个问题,我可以从模板中删除每个 UI 元素,然后将其添加到我的固定文档中。这似乎不是最干净的解决方案,但它是可能的。
然后我想遍历此列表中的每个 UIElement,而不是手动从模板中删除每个元素并将其添加到我的固定文档中。如果标签需要更改,我会这样做,这会让事情变得更容易。
我找到了显示how to iterate through each element的链接
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
但是,这似乎只适用于模板本身的代码!所以这对我想要打印的课堂没有帮助。当然,我可以创建一个全局范围的变量并以这种方式传递我的 UIelements 列表,但这越来越不干净了。最重要的是,我只能在模板类的 Windows_Loaded 事件中调用此方法。 Windows_Loaded 只有在WindowInstance.ShowDialog(); 被调用时才会被调用,这当然会在屏幕上显示模板,这也是我不能拥有的。
有没有办法完成我正在尝试的事情,或者我最好放弃整个模板的想法并通过后面的代码定位所有内容。
已更新虽然这里的一些答案为我指明了正确的方向,但我需要更多的挖掘才能完成我想做的事情。解决方案:
我在 Lena 的回答和another post 的帮助下拼凑了我的解决方案,another post
要获得一个适合自己的示例,请使用 Lena 的 View.xaml、View.xaml.cs、ViewModel.cs,然后使用我自己的方法来打印 View.xaml
private void StackOverFlow()
{
string palletID = "00801004018000020631";
PrintDialog pd = new PrintDialog();
FixedDocument fixedDoc = new FixedDocument();
PageContent pageContent = new PageContent();
FixedPage fixedPage = new FixedPage();
fixedDoc.DocumentPaginator.PageSize = new System.Windows.Size(pd.PrintableAreaWidth, pd.PrintableAreaHeight);
fixedPage.Width = fixedDoc.DocumentPaginator.PageSize.Width;
fixedPage.Height = fixedDoc.DocumentPaginator.PageSize.Height;
fixedPage.Width = 4.0 * 96;
fixedPage.Height = 3.0 * 96;
var pageSize = new System.Windows.Size(4.0 * 96.0, 3.0 * 96.0);
View v = new View();
ViewModel vm = new ViewModel(); //This would be the label object with
//set all ViewModel.cs Props here
vm.Text1 = "MyText1";
vm.Text2 = "MyText2";
v.DataContext = vm;
v.Height = pageSize.Height;
v.Width = pageSize.Width;
v.UpdateLayout();
fixedPage.Children.Add(v);
((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
//Use the XpsDocumentWriter to "Write" to a specific Printers Queue to Print the document
XpsDocumentWriter dw1 = PrintQueue.CreateXpsDocumentWriter(new System.Printing.PrintQueue(new System.Printing.PrintServer(), "CutePDF Writer"));
dw1.Write(fixedDoc);
}
【问题讨论】:
-
我使用 MVVM 方法将我的窗口打印到 xps 文件。我创建了一个 xaml 视图,其中包含一些控件和模板表,它可以包含我需要的任意数量的项目。这个 View 的 DataContext 保存了所有的数据。使用 XpsDocumentWriter 和 FixedPage 可以很容易地打印此视图,尤其是如果您不必关心文档的分页。