2

My application prints (to a printer) the information shown on screen (using the Canvas control) N times.

The process is

The user clicks a button (called Print).
Update the Canvas with text (normally from a database but for the code below, it's hard coded)
Print to printer
Update the Canvas with new text (again from a database but for the code below, it's hard coded) Print to printer

However, I can't get this to work as explained in the above process- the printer only prints the last update made.

To make this issue replicable, I enclose the code below

My XAML

<Window x:Class="WpfApplication4.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Canvas Margin="0,0,0,88" Name="canvas1">
        <TextBlock Text="Hello World" Name="TextBlock1" />
    </Canvas>
    <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="0,245,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
</Grid>
</Window>

and my code behind

using System;
using System.Windows;
using System.Printing;
using System.Windows.Threading;
using System.Windows.Controls;

namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        PrintDialog dialog = new PrintDialog();
        for (int i = 1; i < 3; i++)
        {
            //showing this message box fixes the issue
            //MessageBox.Show("01");
            updateTextblock(i);

            //use the dispatcher object to ensure all renders and databinding are completed before sending to print   
            DispatcherOperation disO;
            disO = Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(delegate
            {
                print(dialog);
            }
            ));   
            disO.Wait()
        }
    }

    private void print(PrintDialog dialog)
    {
        //select printer auotmatically
        PrintQueue queue = new LocalPrintServer().GetPrintQueue("Canon MG160 series WS");
        //assign the printer  
        dialog.PrintQueue = queue;

        dialog.PrintVisual(canvas1, "");
    }

    private void updateTextblock(int i)
    {
        TextBlock1.Text = "Number " + i.ToString();
    }
}
}    

The only thing which prints is Number 2

Although it has iterated and updated the canvas with Number 1 it never prints (a blank page is printed).

Any ideas what it is I need to do so each Canvas prints? Although I can get it to work by showing the messagebox it defeats the purpose of it being automated.

EDIT: I am now getting an error message from my printer - "Another computer is using the printer." According to other websites, I have to wait until one job finishes and then the second will start automatically but sadly, it never does.

JSW189
  • 6,267
  • 11
  • 44
  • 72
Dave
  • 8,163
  • 11
  • 67
  • 103

4 Answers4

1

Use PrintDialog dialog = new PrintDialog(); inside for loop Use this function

 private void button1_Click(object sender, RoutedEventArgs e)
    {

        for (int i = 1; i < 3; i++)
        {
           PrintDialog dialog = new PrintDialog();
            //showing this message box fixes the issue
            //MessageBox.Show("01");
            updateTextblock(i);

            //use the dispatcher object to ensure all renders and databinding are completed before sending to print   
            Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(delegate
            {
                print(dialog);
            }
            ));   
        }
    }
Md Kamruzzaman Sarker
  • 2,387
  • 3
  • 22
  • 38
1

The answer (sorry the code is not exactly the same as the question but it's so simple it should be easy to follow. Thank you every one.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;


namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < 2; i++)
            {
            result res = null;     
            if (i == 0)
            res = new result { Comments = "First Time Round" };

            if (i == 1)
                res = new result { Comments = "Total hard type" };

            Dispatcher.Invoke(DispatcherPriority.Loaded, new Action(delegate
                {   
                    this.DataContext = res;
                }
            ));

            System.Threading.Thread.Sleep(500);

            Dispatcher.Invoke(DispatcherPriority.Loaded, new Action(delegate
            {
                PrintDialog dialog = new PrintDialog();
                dialog.PrintVisual(this.canvas1, "");
            }
        ));
            System.Threading.Thread.Sleep(500);

            }
        }
    }

    class result
    {
        public string Comments { get; set; }
    }
}
Dave
  • 8,163
  • 11
  • 67
  • 103
0

Your UpdateText method is all wrong. Each time you call the method you are creating a new string in the textblock. So as a result all you will see is the last call to the routine.

Instead you should be appending to the text instead of replacing the text.

SASS_Shooter
  • 2,186
  • 19
  • 30
  • But the print method is called during the same loop. I am expecting 2 pages to print, one with number 1 and then again with number 2. If I append, then I'll get number 1 on the first page and then number 1 number 2 on the second? – Dave Jun 05 '12 at 19:17
0

The BeginInvoke returns a DispatcherOperation. If you call Wait on it before continuing in the for loop, the textbox will not be updated, until the first print has been performed.

erikH
  • 2,286
  • 1
  • 17
  • 19
  • I tried this and it also didn't make a difference. Sorry but thank you for the reply – Dave Jun 06 '12 at 06:44
  • It may be worth a try to add an "empty" delegate with the lowest priority, so that the printing has completed (for sure?) before the next iteration of the for loop. – erikH Jun 06 '12 at 21:15
  • That should at least be the problem, that the print call has not entirely completed... – erikH Jun 06 '12 at 21:17
  • I will have another go today at this - I agree, the logic is sound but I can't work out why it's not working - Thank you for keeping with me on this. – Dave Jun 07 '12 at 14:50
  • My button1_Click method is now updated as per the suggestion but this doesn't help sadly – Dave Jun 07 '12 at 15:31