728x90
반응형
728x170
TestProject.zip
다운로드
result.xps
다운로드
▶ PlainTextDocumentPaginator.cs
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Printing;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 단순 텍스트 문서 페이지 지정자
/// </summary>
public class PlainTextDocumentPaginator : DocumentPaginator
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Declaration
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Class
/// <summary>
/// 프린트 라인
/// </summary>
private class PrintLine
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 문자열
/// </summary>
public string String;
/// <summary>
/// 플래그
/// </summary>
public bool Flag;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - PrintLine(source, flag)
/// <summary>
/// 생성자
/// </summary>
/// <param name="source">소스 문자열</param>
/// <param name="flag">플래그</param>
public PrintLine(string source, bool flag)
{
String = source;
Flag = flag;
}
#endregion
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 중단 문자 배열
/// </summary>
private char[] breakCharacterArray = new char[] { ' ', '-' };
/// <summary>
/// 텍스트
/// </summary>
private string text = string.Empty;
/// <summary>
/// 헤더 텍스트
/// </summary>
private string headerText = null;
/// <summary>
/// 타입 페이스
/// </summary>
private Typeface typeface = new Typeface("");
/// <summary>
/// EM 크기
/// </summary>
private double emSize = 11;
/// <summary>
/// 페이지 크기
/// </summary>
private Size pageSize = new Size(8.5d * 96d, 11d * 96d);
/// <summary>
/// 최대 크기
/// </summary>
private Size maximumSize = new Size(0, 0);
/// <summary>
/// 마진 두께
/// </summary>
private Thickness marginThickness = new Thickness(96d);
/// <summary>
/// 프린트 티켓
/// </summary>
private PrintTicket printTicket = new PrintTicket();
/// <summary>
/// 텍스트 랩핑
/// </summary>
private TextWrapping textWrapping = TextWrapping.Wrap;
/// <summary>
/// 문서 페이지 리스트
/// </summary>
private List<DocumentPage> documentPageList;
/// <summary>
/// 테두리 펜
/// </summary>
private Pen borderPen = new Pen(Brushes.Transparent, 1);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 텍스트 - Text
/// <summary>
/// 텍스트
/// </summary>
public string Text
{
set
{
this.text = value;
}
get
{
return this.text;
}
}
#endregion
#region 텍스트 랩핑 - TextWrapping
/// <summary>
/// 텍스트 랩핑
/// </summary>
public TextWrapping TextWrapping
{
set
{
this.textWrapping = value;
}
get
{
return this.textWrapping;
}
}
#endregion
#region 여백 - Margin
/// <summary>
/// 여백
/// </summary>
public Thickness Margin
{
set
{
this.marginThickness = value;
}
get
{
return this.marginThickness;
}
}
#endregion
#region 타입 페이스 - Typeface
/// <summary>
/// 타입 페이스
/// </summary>
public Typeface Typeface
{
set
{
this.typeface = value;
}
get
{
return this.typeface;
}
}
#endregion
#region EM 크기 - EMSize
/// <summary>
/// EM 크기
/// </summary>
public double EMSize
{
set
{
this.emSize = value;
}
get
{
return this.emSize;
}
}
#endregion
#region 프린트 티켓 - PrintTicket
/// <summary>
/// 프린트 티켓
/// </summary>
public PrintTicket PrintTicket
{
set
{
this.printTicket = value;
}
get
{
return this.printTicket;
}
}
#endregion
#region 헤더 텍스트 - HeaderText
/// <summary>
/// 헤더 텍스트
/// </summary>
public string HeaderText
{
set
{
this.headerText = value;
}
get
{
return this.headerText;
}
}
#endregion
#region 페이지 수 유효 여부 - IsPageCountValid
/// <summary>
/// 페이지 수 유효 여부
/// </summary>
public override bool IsPageCountValid
{
get
{
if(this.documentPageList == null)
{
Format();
}
return true;
}
}
#endregion
#region 페이지 수 - PageCount
/// <summary>
/// 페이지 수
/// </summary>
public override int PageCount
{
get
{
if(this.documentPageList == null)
{
return 0;
}
return this.documentPageList.Count;
}
}
#endregion
#region 페이지 크기 - PageSize
/// <summary>
/// 페이지 크기
/// </summary>
public override Size PageSize
{
set
{
this.pageSize = value;
}
get
{
return this.pageSize;
}
}
#endregion
#region 소스 - Source
/// <summary>
/// 소스
/// </summary>
public override IDocumentPaginatorSource Source
{
get
{
return null;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 페이지 구하기 - GetPage(pageNumber)
/// <summary>
/// 페이지 구하기
/// </summary>
/// <param name="pageNumber">페이지 번호</param>
/// <returns>DocumentPage 객체</returns>
public override DocumentPage GetPage(int pageNumber)
{
return this.documentPageList[pageNumber];
}
#endregion
#region FormattedText 객체 구하기 - GetFormattedText(text)
/// <summary>
/// FormattedText 객체 구하기
/// </summary>
/// <param name="text">테스트</param>
/// <returns>FormattedText 객체</returns>
private FormattedText GetFormattedText(string text)
{
return new FormattedText
(
text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
this.typeface,
this.emSize,
Brushes.Black
);
}
#endregion
#region 라인 처리하기 - ProcessLine(sourceLine, printableWidth, printLineList)
/// <summary>
/// 라인 처리하기
/// </summary>
/// <param name="sourceLine">소스 라인</param>
/// <param name="printableWidth">인쇄 가능한 너비</param>
/// <param name="printLineList">프린트 라인 리스트</param>
private void ProcessLine(string sourceLine, double printableWidth, List<PrintLine> printLineList)
{
sourceLine = sourceLine.TrimEnd(' ');
if(TextWrapping == TextWrapping.NoWrap)
{
#region TextWrapping.NoWrap
do
{
int length = sourceLine.Length;
while(GetFormattedText(sourceLine.Substring(0, length)).Width > printableWidth)
{
length--;
}
printLineList.Add(new PrintLine(sourceLine.Substring(0, length), length < sourceLine.Length));
sourceLine = sourceLine.Substring(length);
}
while(sourceLine.Length > 0);
#endregion
}
else
{
#region TextWrapping.Wrap, TextWrapping.WrapWithOverflow
do
{
int length = sourceLine.Length;
bool flag = false;
while(GetFormattedText(sourceLine.Substring(0, length)).Width > printableWidth)
{
int index = sourceLine.LastIndexOfAny(this.breakCharacterArray, length - 2);
if(index != -1)
{
length = index + 1;
}
else
{
index = sourceLine.IndexOfAny(this.breakCharacterArray);
if(index != -1)
{
length = index + 1;
}
if(TextWrapping == TextWrapping.Wrap)
{
while(GetFormattedText(sourceLine.Substring(0, length)).Width > printableWidth)
{
length--;
}
flag = true;
}
break;
}
}
printLineList.Add(new PrintLine(sourceLine.Substring(0, length), flag));
sourceLine = sourceLine.Substring(length);
}
while(sourceLine.Length > 0);
#endregion
}
}
#endregion
#region 포맷하기 - Format()
/// <summary>
/// 포맷하기
/// </summary>
private void Format()
{
List<PrintLine> printLineList = new List<PrintLine>();
FormattedText sampleFormattedText = GetFormattedText("W");
double printableWidth = PageSize.Width - Margin.Left - Margin.Right;
if(printableWidth < sampleFormattedText.Width)
{
return;
}
string sourceLine;
Pen pen = new Pen(Brushes.Black, 2);
StringReader stringReader = new StringReader(this.text);
while(null != (sourceLine = stringReader.ReadLine()))
{
ProcessLine(sourceLine, printableWidth, printLineList);
}
stringReader.Close();
double lineHeight = sampleFormattedText.LineHeight + sampleFormattedText.Height;
double printableHeight = PageSize.Height - Margin.Top - Margin.Bottom;
int pageLineCount = (int)(printableHeight / lineHeight);
if(pageLineCount < 1)
{
return;
}
int pageCount = (printLineList.Count + pageLineCount - 1) / pageLineCount;
double startX = Margin.Left;
double startY = Margin.Top;
this.documentPageList = new List<DocumentPage>();
for(int page = 0, line = 0; page < pageCount; page++)
{
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
#region 페이지 내 일정 영역만 출력하면 페이지가 정상적으로 출력되지 않기 때문에 아래 코드를 실행한다.
drawingContext.DrawRectangle(Brushes.Transparent, this.borderPen, new Rect(PageSize));
#endregion
if(HeaderText != null && HeaderText.Length > 0)
{
FormattedText formattedText = GetFormattedText(HeaderText);
formattedText.SetFontWeight(FontWeights.Bold);
Point textPoint = new Point(startX, startY - 2 * formattedText.Height);
drawingContext.DrawText(formattedText, textPoint);
}
if(pageCount > 1)
{
FormattedText formattedText = GetFormattedText("Page " + (page + 1) + " of " + pageCount);
formattedText.SetFontWeight(FontWeights.Bold);
Point textPoint = new Point
(
(PageSize.Width + Margin.Left - Margin.Right - formattedText.Width) / 2d,
PageSize.Height - Margin.Bottom + formattedText.Height
);
drawingContext.DrawText(formattedText, textPoint);
}
for(int i = 0; i < pageLineCount; i++, line++)
{
if(line == printLineList.Count)
{
break;
}
string lineString = printLineList[line].String;
FormattedText lineFormattedText = GetFormattedText(lineString);
Point textPoint = new Point(startX, startY + i * lineHeight);
drawingContext.DrawText(lineFormattedText, textPoint);
if(printLineList[line].Flag)
{
double x = startX + printableWidth + 6;
double y = startY + i * lineHeight + lineFormattedText.Baseline;
double length = this.typeface.CapsHeight * this.emSize;
drawingContext.DrawLine(pen, new Point(x, y), new Point(x + length , y - length ));
drawingContext.DrawLine(pen, new Point(x, y), new Point(x , y - length / 2d));
drawingContext.DrawLine(pen, new Point(x, y), new Point(x + length / 2d, y ));
}
}
drawingContext.Close();
DocumentPage documentPage = new DocumentPage(drawingVisual);
this.documentPageList.Add(documentPage);
}
stringReader.Close();
}
#endregion
}
}
728x90
▶ MainWindow.xaml
<Window x:Class="TestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="800"
Height="600"
Title="DocumentPaginator 클래스 : 일반 텍스트 문자열 출력하기"
FontFamily="나눔고딕코딩"
FontSize="16">
<Grid>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBox Name="textBox"
Margin="10"
Width="300"
Height="300"
VerticalContentAlignment="Top"
AcceptsReturn="True" />
<Button Name="printButton"
Margin="10"
Width="100"
Height="30"
Content="인쇄하기" />
</StackPanel>
</Grid>
</Window>
300x250
▶ MainWindow.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 메인 윈도우
/// </summary>
public partial class MainWindow : Window
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainWindow()
/// <summary>
/// 생성자
/// </summary>
public MainWindow()
{
InitializeComponent();
this.printButton.Click += printButton_Click;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 인쇄하기 버튼 클릭시 처리하기 - printButton_Click(sender, e)
/// <summary>
/// 인쇄하기 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void printButton_Click(object sender, RoutedEventArgs e)
{
PrintDialog printDialog = new PrintDialog();
if(printDialog.ShowDialog().GetValueOrDefault())
{
PlainTextDocumentPaginator paginator = new PlainTextDocumentPaginator();
paginator.PrintTicket = printDialog.PrintTicket;
paginator.Text = this.textBox.Text;
paginator.HeaderText = string.Empty;
paginator.Typeface = new Typeface
(
textBox.FontFamily,
textBox.FontStyle,
textBox.FontWeight,
textBox.FontStretch
);
paginator.EMSize = this.textBox.FontSize;
paginator.TextWrapping = this.textBox.TextWrapping;
paginator.Margin = new Thickness(48);
paginator.PageSize = new Size
(
printDialog.PrintableAreaWidth,
printDialog.PrintableAreaHeight
);
printDialog.PrintDocument(paginator, "Sample");
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] XamlReader 클래스 : Load 정적 메소드를 사용해 리소스 형태의 XAML 파일 로드하기 (0) | 2020.08.20 |
---|---|
[C#/WPF] Frame 엘리먼트 : NavigationUIVisibility 속성 사용하기 (0) | 2020.08.20 |
[C#/WPF] x:Code 엘리먼트 : XAML 파일에서 코드 내장하기 (0) | 2020.08.20 |
[C#/WPF] XAML 문자열에서 객체 생성하기 (0) | 2020.08.20 |
[C#/WPF] KeyGesture 클래스 : 단축 키 사용하기 (0) | 2020.08.19 |
[C#/WPF] TextBox 클래스 : GetLineIndexFromCharacterIndex/GetCharacterIndexFromLineIndex 메소드를 사용해 행/열 인덱스 구하기 (0) | 2020.08.19 |
[C#/WPF] FontStretchConverter 클래스 : ConvertToString/ConvertFromString 메소드 사용하기 (0) | 2020.08.19 |
[C#/WPF] FontWeightConverter 클래스 : ConvertToString/ConvertFromString 메소드 사용하기 (0) | 2020.08.19 |
[C#/WPF] 한글 폰트명 리스트 구하기 (0) | 2020.08.19 |
[C#/WPF] DocumentPaginator 클래스 : 배너 문자 출력하기 (0) | 2020.08.18 |
댓글을 달아 주세요