Silverlight 4: Multi page printing (MVVM) или многостраничная печать
WPF, MVVM, Silverlight | создано: 05.10.2010 | опубликовано: 06.10.2010 | обновлено: 13.01.2024 | просмотров: 5418
После выхода Silverlight 4 при разработки некоторого проекта столкнулся с простым вопросом: Как напечатать из Silverlight многостраничный документ? На самом деле, всё просто, достаточно знать некоторые нюансы. Особенно это интересно, если предположить, что печатать должно приложение, которое реализовано по шаблону программирования Model-View-ViewModel (MVVM).
Постановка задачи
Итак, после выхода Silverlight 4 при разработки некоторого проекта столкнулся с простым вопросом: Как напечатать из Silverlight многостраничный документ? На самом деле, всё просто, достаточно знать некоторые нюансы. Особенно это интересно, если предположить, что печатать должно приложение, которое реализовано по шаблону программирования Model-View-ViewModel (MVVM).
Реализация
Для начала шаблон программирования реализуем. Для этого создадим класс ViewModelBase, который реализует интерфейс INotifyPropertyChanged:
using System.ComponentModel;
namespace MultiPagePrinting
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Теперь класс RelayCommand, который реализует интерфейс ICommand.
using System;
using System.Windows.Input;
namespace MultiPagePrinting
{
public class RelayCommand : ICommand
{
public event EventHandler CanExecuteChanged;
Predicate<Object> _canExecute = null;
Action<Object> _executeAction = null;
public RelayCommand(Action<object> executeAction, Predicate<Object> canExecute)
{
_canExecute = canExecute;
_executeAction = executeAction;
}
public bool CanExecute(object parameter)
{
if (_canExecute != null)
return _canExecute(parameter);
return true;
}
public void UpdateCanExecuteState()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
public void Execute(object parameter)
{
if (_executeAction != null)
_executeAction(parameter);
UpdateCanExecuteState();
}
}
}
А теперь, в качестве подопытного класса создадим класс MyItem, с ним и будем “ставить опыты”. Выглядит этот класс так:
using System;
namespace MultiPagePrinting
{
public class MyItem
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ActionDate { get; set; }
public string Description { get; set; }
public MyItem()
{
}
public MyItem(int id, string title, DateTime date, string description)
{
this.ActionDate = date;
this.Description = description;
this.ID = id;
this.Title = title;
}
}
}
Как видите, ничего сложного, нам главное, чтобы было с чем поэкспериментировать. Теперь пришло время сделать модель-представление (ViewModel) главной страницы MainPageViewModel. Наследовать будем его от заготовленного класса ViewModelBase. Вот только пара самых главных методов.
Печать одной записи
Метод, который печатает одну запись из ListBox, я назвал CommandPrintOneExecute:
// Процедура выполнения команды CommandPrintOne
private void CommandPrintOneExecute()
{
// выполнение команды PrintOne
// процедура выполнения команды
PrintDocument doc = new PrintDocument();
doc.PrintPage += (s, arg) =>
{
MyItemControl item = new MyItemControl();
item.DataContext = this.CurrentItem;
arg.PageVisual = item;
};
doc.Print(CurrentItem.Title);
}
Создаем экземпляр класса PrintDocument, в EnventHandler PrintPage подсовываем выбранный (CurrentItem) предварительно обернутый в наш MyItemControl контрол-обертку. И более ничего. Запускаем метод Print, в котором указываем имя печатаемого документа.
Вывод на печать много страниц
Вот так выглядит метод, который печатает много страниц:
// Процедура выполнения команды CommandPrintAll
private void CommandPrintAllExecute()
{
// выполнение команды PrintAll
// процедура выполнения команды
PrintDocument multidoc = new PrintDocument();
int index = 0;
multidoc.PrintPage+=(s,arg)=>{
StackPanel host = new StackPanel();
while (index < Collection.Count)
{
MyItemControl m = new MyItemControl();
m.DataContext = Collection[index];
host.Children.Add(m);
host.Measure(new Size(arg.PrintableArea.Width, double.PositiveInfinity));
if (host.DesiredSize.Height > arg.PrintableArea.Height && host.Children.Count>1)
{
host.Children.Remove(m);
arg.HasMorePages = true;
break;
}
index++;
}
arg.PageVisual = host;
};
multidoc.Print("Список какой-то фигни");
}
Код прост как семь копеек. Создаем экземпляр PrintDocument, потом размещаем объекты на печатном листе. При этом проверяем, вмещается ли (StackPanel по имени host) с дочерними контролами (MyItemControl) на странице или нет. Если нет, то последний убираем, и сообщаем программе (arg.HasMorePages = true), что существуют еще страницы, которые надо печатать. Что и требовалось… Всё работает так как и планировалось…