Reputation: 8461
I have a simple issue, but the solution appears to be tricky. I want to print using the WPF control canvas during a loop; but for each iteration, I want to udpate the canvas control.
If I want to print a canvas control in WPF, I can simply call
PrintDialog dialog = new PrintDialog();
dialog.PrintVisual(this.canvas, "");
And it prints as expected to my default printer. Wonderful.
However, if I want to perform this multiple times in a loop and make an update to the canvas during each iteration, only the final iteration of the loop is printed.
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;
}
Any idea what I need to do to ensure that I get 2 print outs, the first with the txtTextBox.Text value of 0, the second time it has the value of 1?
Upvotes: 1
Views: 2148
Reputation: 8461
OK
I solved it.
I removed all the dispatcher object methods so it runs on a single thread.
To update the canvas, I used the canvas.UpdateLayout() method.
I also ensured that the print had finished before updating the next canvas (the next iteration).
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;
}
I also could have just done thread.sleep(3000) - this worked as it was enough time to ensure the print job had completed, but it was also a little bit 'hopeful' and I wanted something more secure.
Thank you to everyone for your suggestions.
Upvotes: 1
Reputation: 2573
I am about to implement something similar in my application and found out that my previous answer wasn't good enough. The problem for me was that although the canvas is updated in each iteration, it has not yet rendered itself before being sent to PrintVisual
. It surprises me that you get your final iteration printed, I only got the first one. Anyway, this is how I made it work, basically queueing the print command after the already pending render operation:
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);
});
}
Yes it's somewhat similar (but not identical) to SalGad's answer and the post you're referring to, but I'm not able to comment that answer, so please try this out, it works for me.
I also had problems with disappearing prints when using empty description for the print jobs, thus the + i
. Don't know if that is a generic problem, or just something with my printer setup.
I got the idea from this post, which also mentions an alternative solution using ViewBox.
Upvotes: 1
Reputation: 3011
Just taking a shot here, but can you try refreshing the WPF canvas controls at the start of every for loop iteration? Here is the code snippet:
// 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);
}
I am sourcing this idea from here
Upvotes: 0
Reputation: 2573
Just a guess, but it might be worth trying RenderTargetBitmap
to force rendering the canvas in each iteration, and then create an Image with that source, which then can be sent to PrintVisual
. See this post for code example:
Upvotes: 0
Reputation: 2018
If you are going to call PrintVisual multiple times you have to look into PrintDocument and DocumentPaginator.
Upvotes: 0