2012-06-14 304 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