Deborah's Developer MindScape






         Tips and Techniques for Web and .NET developers.

February 19, 2011

Silverlight Simple MVVM Printing

Filed under: C#,Silverlight,VB.NET @ 2:02 pm

Many users want to print information from your line of business (LOB) application. This post covers the simple case where the user wants to print a copy of what they see on the screen. But instead of putting the print code in the code behind file, it follows a Model-View-View/Model (MVVM) approach.

NOTE: This post is part of a series that starts with this prior post. The example in this post uses the application that is built as part of that series.

NOTE: If you are new to MVVM, this prior post provides an introduction.

Silverlight 4 introduced two features that are the basis of this post: printing support and commanding.

Using the built-in commanding feature to support printing requires the following steps:

1) Create a command class that implements the ICommand interface.

2) Create a property of type ICommand in the View/Model class for a PrintCommand.

3) Build a button to launch the printing and bind the Command property of the button to the property created in 2 above.

Creating a Command Class

The code for this class was provided in this prior post and is not repeated here.

Creating a Property in the View/Model

Add three things to the View/Model for each command:

1) Command property.

2) Code to set the command property.

3) Method defined for the command property delegate.

The code is shown below with the statements for 1, 2, and 3 above shown in red.

In C#:

using System;
using System.Collections.ObjectModel;
using System.ServiceModel.DomainServices.Client;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Printing;
using InStepSM.Library;
using InStepSM.SL.Web;

namespace InStepSM.SL.ViewModels
{
    public class StudentsViewModel : ViewModelBase
    {
        private ICommand _PrintCommand;
        public ICommand PrintCommand
        {
            get
            {
                return _PrintCommand;
            }
        }

        private ICommand _SaveCommand;
        public ICommand SaveCommand
        {
            get
            {
                return _SaveCommand;
            }
        }
        
        private StudentContext StudentContextInstance;

        private ObservableCollection<Student> _StudentsList;
        public ObservableCollection<Student> StudentsList
        {
            get
            {
                return _StudentsList;
            }
            set
            {
                if (_StudentsList != value)
                {
                    _StudentsList = value;
                    OnPropertyChanged("StudentsList");
                }
            }
        }

        public StudentsViewModel()
        {
            LoadData();
            DefineCommands();
        }

        private void DefineCommands()
        {
            _SaveCommand = new DelegateCommand<Student>
                            (OnSaveCommand);
            _PrintCommand = new DelegateCommand<Panel>
                            (OnPrintCommand);
        }

        /// <summary>
        /// Loads the data for the application.
        /// </summary>
        private void LoadData()
        {
            if (IsInDesignModeStatic)
            {
                LoadDesignData();
            }
            else
            {
                // Load the student data asynchronously
                StudentContextInstance = new StudentContext();
                var loadop =
                  StudentContextInstance.Load(StudentContextInstance.
                                   GetStudentsQuery(),
                                   OnStudentsLoaded, null);
            }
        }

        /// <summary>
        /// Loads temporary data for use in the designer.
        /// </summary>
        /// <remarks></remarks>
        private void LoadDesignData()
        {
            //Design mode data
            ObservableCollection<Student> temp =
                        new ObservableCollection<Student>();
            temp.Add(new Student
            {
                LastName = "Baggins",
                FirstName = "Bilbo",
                Age = 111,
                Email = "testemail@live.com",
                RegistrationDate = DateTime.Now
            });
            temp.Add(new Student
            {
                LastName = "Baggins",
                FirstName = "Frodo",
                Age = 32,
                Email = "testemail@yahoo.com",
                RegistrationDate = DateTime.Now
            });
            StudentsList = temp;
        }

        private void OnPrintCommand(Panel p)
        {
            PrintDocument pd = new PrintDocument();
            pd.PrintPage += (s, e) =>
                {
                    p.Width = e.PrintableArea.Width;
                    p.Height = e.PrintableArea.Height;
                    e.PageVisual = p;
                    e.HasMorePages = false;
                };

            pd.Print("Student List");
        }

        private void OnStudentsLoaded(LoadOperation lo)
        {
            StudentsList = 
   new ObservableCollection<Student>(StudentContextInstance.Students);
        }

        private void OnSaveCommand(Student s)
        {
            StudentContextInstance.SubmitChanges();
        }

    }
}

In VB:

Imports System.Collections.ObjectModel
Imports System.ServiceModel.DomainServices.Client
Imports InStepSM.SL.Web
Imports System.Windows.Printing
Imports System.Windows.Controls

Namespace ViewModels
    Public Class StudentsViewModel
        Inherits ViewModelBase

        Private _PrintCommand As ICommand
        ”’ <summary>
        ”’ Processes the Save command
        ”’ </summary>
        Public ReadOnly Property PrintCommand() As ICommand
            Get
                Return _PrintCommand
            End Get
        End Property

        Private _StudentsList As ObservableCollection(Of Student)
        Public Property StudentsList() As _
                            
ObservableCollection(Of Student)
            Get
                Return _StudentsList
            End Get
            Set(ByVal value As ObservableCollection(Of Student))
                If _StudentsList IsNot value Then
                    _StudentsList = value
                    OnPropertyChanged("StudentsList")
                End If
            End Set
        End Property

        Private StudentContextInstance As StudentContext

        Private _SaveCommand As ICommand
        ”’ <summary>
        ”’ Processes the Save command
        ”’ </summary>
        Public ReadOnly Property SaveCommand() As ICommand
            Get
                Return _SaveCommand
            End Get
        End Property

        Public Sub New()
            LoadData()
            DefineCommands()
        End Sub

        Private Sub DefineCommands()
            _SaveCommand = New DelegateCommand(Of Student)(
                            AddressOf OnSaveCommand)
            _PrintCommand = New DelegateCommand(Of Panel)(
                            AddressOf OnPrintCommand)
        End Sub

        ”’ <summary>
        ”’ Loads the data for the application.
        ”’ </summary>
        Private Sub LoadData()
            If IsInDesignModeStatic Then
                LoadDesignData()
            Else
                ‘ Load the student data asynchronously
                StudentContextInstance = New StudentContext
                Dim loadop =
                 StudentContextInstance.Load(StudentContextInstance.
                               GetStudentsQuery(),
                               AddressOf OnStudentsLoaded, Nothing)
            End If
        End Sub

        ”’ <summary>
        ”’ Loads temporary data for use in the designer.
        ”’ </summary>
        ”’ <remarks></remarks>
        Private Sub LoadDesignData()
            ‘ Design mode data
            Dim temp As New ObservableCollection(Of Student)
            temp.Add(New Student With {.LastName = "Baggins",
                                       .FirstName = "Bilbo",
                                       .Age = 111,
                                       .Email = "testemail@live.com",
                                       .RegistrationDate = Now()})
            temp.Add(New Student With {.LastName = "Baggins",
                                       .FirstName = "Frodo",
                                       .Age = 32,
                                       .Email = "testemail@yahoo.com",
                                       .RegistrationDate = Now()})
            StudentsList = temp

        End Sub

        Private Sub OnPrintCommand(ByVal p As Panel)
            Dim pd As PrintDocument = New PrintDocument()
            AddHandler pd.PrintPage,
                Sub(s, e)
                    p.Width = e.PrintableArea.Width
                    p.Height = e.PrintableArea.Height
                    e.PageVisual = p
                    e.HasMorePages = False

                End Sub
            pd.Print("Student List")
        End Sub

        Private Sub OnStudentsLoaded(ByVal lo As LoadOperation)
            StudentsList = 
New ObservableCollection(Of Student)(StudentContextInstance.Students)
        End Sub

        Private Sub OnSaveCommand(ByVal s As Student)
            StudentContextInstance.SubmitChanges()
        End Sub

    End Class
End Namespace

The PrintCommand is the property that implements ICommand. The UI can be bound to this property.

The DefineCommands method assigns the PrintCommand to a new instance of the DelegateCommand class. Notice that it uses a Panel as the parameter. That allows passing any control that inherits from Panel to the PrintCommand. Controls that inherit from Panel include Grid and StackPanel.

The OnPrintCommand is the method to be executed when the command occurs. This method creates an instance of PrintDocument, which is the primary class for handling printing in Silverlight. It then defines a delegate for the PrintPage event. Finally, it calls the Print method of the PrintDocument to start the printing process.

The PrintPage event is generated for each page to be printed. When the PrintPage event occurs, the delegate code sets the size of the passed in control to fit the printable area of the page. It then assigns the PageVisual to the control. All controls in the tree of the control assigned to the PageVisual are printed. Setting the HasMorePages to false indicates that there is only one page to print.

Binding to the Command

This last step is to define a control in the xaml that launchs the printing. In this example, a Print button is used. The xaml for the button is as follows:

<Button Command="{Binding PrintCommand}"
        CommandParameter="{Binding ElementName=LayoutRoot}"
        Content="Print"
        HorizontalAlignment="Right"
        Name="PrintButton"
        Margin="10"
        Width="60" />

The Command property of the Button is bound to the PrintCommand property from the View/Model. The CommandParameter property of the Button is bound to the LayoutRoot element of the page, which is the main grid on the page. The resulting printed output is shown below:

image

But maybe you don’t want the entire page with the title and buttons. If so, just assign a different control to the CommandParameter.

For example, you can put a StackPanel around just the DataGrid and pass the name of the StackPanel in as the CommandParameter. The resulting printed output then only includes the DataGrid.

image

Use this technique any time you need to print the content or some portion of the content of your Silverlight page to the printer.

Enjoy!

RSS feed for comments on this post. TrackBack URI

Leave a comment

© 2020 Deborah's Developer MindScape   Provided by WPMU DEV -The WordPress Experts   Hosted by Microsoft MVPs