Microsoft Silverlight 4.0 supports Printing with the help of Printing API. The article will basically deals with step by step approach in achieving Print functionality with MVVM pattern.
- Start Visual Web Developer 2010 Express and create a Silverlight Application
- Select Silverlight 4 from Silverlight version dropdown and click Ok
- Create three folders, Model, ViewModel and Command.
- Right click on Model folder and create a class for model. Let name it as Employee.
and add the following properties
1: public class Employee
2: {3: /// <summary>
4: /// Gets or sets Employee Id.
5: /// </summary>
6: public int Id { get; set; }
7:8: /// <summary>
9: /// Gets or sets Employee's First name.
10: /// </summary>
11: public String FirstName { get; set; }
12:13: /// <summary>
14: /// Gets or sets Employee's Last name.
15: /// </summary>
16: public String LastName { get; set; }
17:18: /// <summary>
19: /// Gets or sets Location of Employee.
20: /// </summary>
21: public String Location { get; set; }
22:23: /// <summary>
24: /// Gets Employee's full name.
25: /// </summary>
26: public String FullName { get { return FirstName + " " + LastName; } }
27:28: /// <summary>
29: /// Returns a collection of dummy details
30: /// </summary>
31: /// <returns>Collection of Employee</returns>
32: public static Collection<Employee> GetEmployeeDetails()
33: {34: Collection<Employee> empList = new Collection<Employee>()
35: {36: new Employee() { Id=001, FirstName = "Amanda",
37: LastName = "Hartshorn", Location="United States" },
38: new Employee() { Id=002, FirstName = "Binu",
39: LastName = "Babu", Location="India" },
40: new Employee() { Id=003, FirstName = "Nihas",
41: LastName = "Alangaden", Location="India" },
42: new Employee() { Id=004, FirstName = "Parvathi",
43: LastName = "Mahesh", Location="United States" },
44: new Employee() { Id=005, FirstName = "Tony",
45: LastName = "Xavier", Location="India" }
46: };47:48: return empList;
49: }50: } - Right click on ViewModel folder in the Silverlight project create a BaseViewModel class
and implement INotifyPropertyChanged interface as shown below
1: public class BaseViewModel : INotifyPropertyChanged
2: {3: /// <summary>
4: /// This event occurs when a property value changes
5: /// </summary>
6: public event PropertyChangedEventHandler PropertyChanged;
7:8: protected void OnPropertyChanged(string name)
9: {10: if (PropertyChanged!= null)
11: {12: PropertyChanged(this, new PropertyChangedEventArgs(name));
13: }14: }15: } - Create MainPageViewModel class inside ViewModel folder and Command class inside Command folder.
- Implement ICommand interface in Command class as shown below
1: public class Command : ICommand
2: {3: private bool m_canExecuteCache;
4: private Action<object> m_executeAction;
5: private Func<object, bool> m_canExecute;
6:7: /// <summary>
8: /// This event occurs when changes occur that
9: /// affect whether the command should execute.
10: /// </summary>
11: public event EventHandler CanExecuteChanged;
12:13: /// <summary>
14: /// Initializes a new instance of <see cref="Command"/> class.
15: /// </summary>
16: /// <param name="canExecute">
17: /// Encapsulates a method that has one
18: /// parameter and returns a value of the type bool.
19: /// </param>
20: /// <param name="executeAction">
21: /// Encapsulates a method that takes a single
22: /// parameter and does not return a value.
23: /// </param>
24: public Command(Func<object, bool> canExecute, Action<object> executeAction)
25: {26: m_canExecute = canExecute;27: m_executeAction = executeAction;28: }29:30: /// <summary>
31: /// This method determines whether the
32: /// command can execute in its current state.
33: /// </summary>
34: /// <param name="parameter">
35: /// Data used by the command. If the command does not
36: /// require data to be passed, this object can be set to null.
37: /// </param>
38: /// <returns>
39: /// true if this command can be executed; otherwise, false.
40: /// </returns>
41: public bool CanExecute(object parameter)
42: {43: bool enable = m_canExecute(parameter);
44:45: if (m_canExecuteCache != enable)
46: {47: m_canExecuteCache = enable;48:49: if (CanExecuteChanged != null)
50: {51: CanExecuteChanged(this, new EventArgs());
52: }53: }54:55: return m_canExecuteCache;
56: }57:58: /// <summary>
59: /// This method will be called when the command is invoked.
60: /// </summary>
61: /// <param name="parameter">
62: /// Data used by the command. If the command does not
63: /// require data to be passed, this object can be set to null.
64: /// </param>
65: public void Execute(object parameter)
66: {67: m_executeAction(parameter);68: }69: } - Create a property for Print Command and another one for Employees collection in the view model. Create an instance of Command and pass the methods which handles can execute and print.
1: public class MainPageViewModel : BaseViewModel
2: {3: /// <summary>
4: /// Initializes a new instance of <see cref="MainPageViewModel"/> class.
5: /// </summary>
6: public MainPageViewModel()
7: {8: //Gets dummy data from model
9: Employees = Employee.GetEmployeeDetails();10: //Setting the Command to the property
11: PrintCommand = new Command.Command(CanPrint, Print);
12: }13:14: /// <summary>
15: /// Gets or sets a collection of Employee.
16: /// </summary>
17: public Collection<Employee> Employees { get; private set; }
18:19: /// <summary>
20: /// Gets or sets the Print Command.
21: /// </summary>
22: public ICommand PrintCommand { get; private set; }
23:24: #region Private Methods
25:26: /// <summary>
27: /// Method which is called when the command is invoked.
28: /// </summary>
29: /// <param name="obj">Data used for Printing</param>
30: private void Print(object obj)
31: {32: //Creates a new instance of the System.Windows.Printing.PrintDocument class.
33: PrintDocument document = new PrintDocument();
34:35: //Event handler which fires when each page is printing.
36: document.PrintPage += (s, arg) => { arg.PageVisual = obj as UIElement; };
37:38: // Starts the printing process for the specified
39: // document by opening the print dialog box.
40: document.Print("Print");
41: }42:43: /// <summary>
44: /// Method which determines whether the
45: /// command can execute in its current state.
46: /// </summary>
47: /// <param name="obj">Data used for Printing</param>
48: /// <returns>true if the command can be executed; otherwise, false</returns>
49: private bool CanPrint(object obj)
50: {51: return true;
52: }53:54: #endregion
55: } - Build the Solution and import ViewModel namespace in MainPage.xaml as shown below
1: xmlns:vm="clr-namespace:PrintApplication.ViewModel"Set the DataContext of the MainPage usercontrol.
1: <UserControl.DataContext>
2: <vm:MainPageViewModel />
3: </UserControl.DataContext>
- Add reference to System.Windows.Controls.Data.dll to the Silverlight project and
import System.Windows.Controls.Data as shown below for adding DataGrid Control to list the Employee details.
1: xmlns:data="clr-namespace:System.Windows.Controls; assembly=System.Windows.Controls.Data" - Add a TextBlock for displaying Title, DataGrid for displaying the Employees Collection and a button for handling Print action in MainPage.xaml.
1: <UserControl x:Class="PrintApplication.MainPage"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6: xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
7: xmlns:vm="clr-namespace:PrintApplication.ViewModel" mc:Ignorable="d">
8: <UserControl.DataContext>
9: <vm:MainPageViewModel />
10: </UserControl.DataContext>
11: <Grid x:Name="LayoutRoot" Background="White" Height="270">
12: <Grid.RowDefinitions>
13: <RowDefinition Height="50" />
14: <RowDefinition />
15: <RowDefinition Height="50" />
16: </Grid.RowDefinitions>
17: <TextBlock x:Name="trbBlock" Text="Printing API Sample" FontSize="18"
18: Margin="3,10,3,14" HorizontalAlignment="Center" Height="26" />
19: <StackPanel x:Name="DisplayPanel" Grid.Row="1" HorizontalAlignment="Center">
20: <data:DataGrid ItemsSource="{Binding Path=Employees}"
21: AutoGenerateColumns="False">
22: <data:DataGrid.Columns>
23: <data:DataGridTextColumn Header="Id" Width="50"
24: Binding="{Binding Id}" />
25: <data:DataGridTextColumn Header="First Name" Width="100"
26: Binding="{Binding FirstName}" />
27: <data:DataGridTextColumn Header="Last Name" Width="100"
28: Binding="{Binding LastName}" />
29: <data:DataGridTextColumn Header="Location" Width="100"
30: Binding="{Binding Location}" />
31: </data:DataGrid.Columns>
32: </data:DataGrid>
33: </StackPanel>
34: <Button Content="Print" Grid.Row="2" Width="100" Height="30"
35: Command="{Binding PrintCommand}"
36: CommandParameter="{Binding ElementName=DisplayPanel}" />
37: </Grid>
38: </UserControl>
- Run the solution and click the Print button to get the Print dialog box.
Thanks
Bimal