2012-06-14 201 views
1

我有一个简单的问题,但解决方案似乎很棘手。我想在循环中使用WPF控件画布进行打印;但是对于每次迭代,我想要画布控件。WPF - 循环打印

如果我想打印在WPF画布控制,我可以简单地调用

PrintDialog dialog = new PrintDialog(); 
dialog.PrintVisual(this.canvas, ""); 

它打印效果与预期到我的默认打印机。精彩。

但是,如果我想在循环中多次执行此操作并在每次迭代过程中对画布进行更新,则只会打印循环的最终迭代。

private void methodName() 
    { 
     for (int i = 0; i < 2; i++) 
     { 
      updateTextBox(i.ToString()); 
      PrintDialog dialog = new PrintDialog(); 
      dialog.PrintVisual(this.canvas, ""); 
     } 
    } 

    private void updateTextBox(string text) 
    { 
     txtTextBox.Text = text; 
    } 

任何想法,我需要做什么来确保我得到2个打印输出时,先用0 txtTextBox.Text值,它的值为1,第二次?

+0

PrintVisual是一个异步函数吗? MSDN没有提到它。 – Vlad

+0

http://msdn.microsoft.com/en-us/library/system.windows.controls.printdialog.printvisual.aspx print是要执行的最后一个命令,因此它只是'拾取'最终的迭代,因为是最后要做的事情。这对我的应用程序来说并不合适。我曾尝试使用DispatcherOperation类来改变优先级,但这没有帮助。 – Dave

+0

好吧,我无法在文档中看到有关异步行为的信息。你确定这不是一个错误? – Vlad

回答

1

OK

我解决了它。

我删除了所有调度程序对象方法,因此它在单个线程上运行。

要更新画布,我使用了canvas.UpdateLayout()方法。

我还确保在更新下一个画布之前完成了打印(下一次迭代)。

private void methodName() 
{ 
    for (int i = 0; i < 2; i++) 
    { 
     updateTextBox(i.ToString()); 

     this.canvas.UpdateLayout(); 

     PrintDialog dialog = new PrintDialog(); 
     dialog.PrintVisual(this.canvas, "ABC"); 

     dialog.PrintQueue.Refresh(); 

     while (dialog.PrintQueue.NumberOfJobs != 0) 
     { 
      bool isQueued = false; 
      foreach (var job in dialog.PrintQueue.GetPrintJobInfoCollection()) 
      { 
       if (job.Name == "ABC") 
        isQueued = true; 
      } 

      if (!isQueued) 
       break; 

      Thread.Sleep(500); 
      dialog.PrintQueue.Refresh(); 
     } 
    } 
} 

private void updateTextBox(string text) 
{ 
    txtTextBox.Text = text; 
} 

我也刚刚做了Thread.Sleep(3000) - 这个工作,因为它是有足够的时间,以确保打印作业已完成,但也有点“希望”,我想更多的东西安全。

谢谢大家的建议。

0

如果您打算多次调用PrintVisual,则必须查看PrintDocument和DocumentPaginator。

+0

...... OP的代码有什么问题? – Vlad

+0

我没有想到我可以一起使用PrintVisual和PrintDocument ...你是说我需要使用PrintDocument来代替(对不起,如果这个问题很挑剔,但我觉得我在这里没有深度) – Dave

+0

我可以做,我们在页面上提供了一些建议 - 无论这是否是一种简洁的优雅解决方案,我认为这取决于程序员,但如果这能起作用,那么它就可行! – Dave

0

只是一个猜测,但它可能是值得尝试RenderTargetBitmap强制渲染画布在每次迭代,然后创建一个与该源的图像,然后可以发送到PrintVisual。看到这个帖子的代码示例:

Printing viewport

0

只是采取在这里拍摄,但你可以尝试在每一个for循环迭代开始刷新WPF画布控件?以下是代码片段:

// declare this 
public static class ExtensionMethods 
{ 
    private static Action EmptyDelegate = delegate() { }; 

    public static void Refresh(this UIElement uiElement) 
    { 
     uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate); 
    } 
} 

// the loop 
for (int i = 0; i < 2; i++) 
    { 
     updateTextBox(i.ToString()); 
     PrintDialog dialog = new PrintDialog(); 
     dialog.PrintVisual(this.canvas, ""); 
    } 
} 

// update this method 
private void updateTextBox(string text) 
{ 
    txtTextBox.Text = text; 
    txtTextBox.Refresh(); 
    Thread.Sleep(500); 
} 

我从here

+0

嗨,没有这没有帮助 - 我竟然尝试simialr - 看到我原来的问题(这似乎没有得到答案) - http://stackoverflow.com/questions/10902791/c-sharp-printing-with-wpf谢谢尽管你需要你的帮助。 – Dave

1

采购这样的想法,我要实现我的应用程序类似的东西,并发现我以前的答案是不够好。对我而言,问题在于虽然画布在每次迭代中都会更新,但在发送到PrintVisual之前尚未呈现出来。让我感到惊讶的是,你得到最后的迭代印刷,我只得到第一个。无论如何,这是我如何做它的工作,已经挂起的渲染操作后,基本上排队打印命令:

for (int i = 0; i < 2; i++) 
{ 
    updateTextBox(i.ToString()); 
    this.canvas.InvalidateVisual(); // Maybe not needed in your case 

    PrintDialog dialog = new PrintDialog(); 

    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, (Action)delegate() 
    { 
    dialog.PrintVisual(this.canvas, "" + i); 
    }); 
} 

是的,它有点类似(但不相同)SalGad的答案,你指到了后,但我无法评论这个答案,所以请尝试一下,它适用于我。

对于打印作业使用空描述(即+ i)时,我也遇到了印件消失的问题。不知道这是一个通用问题,还是仅仅是我的打印机设置。

我从this post得到了这个想法,它也提到了一个使用ViewBox的替代解决方案。

+0

我已经做了一些修复它,但我认为你的答案可能更优雅。我将在今天完成工作时对此进行测试 - 因为我对其他人感兴趣,所以我仍然会公布我的答案。我真的不能感谢你的帮助。 – Dave