반응형

찰스 페졸드의 WPF 를 읽으면서 정리한 인쇄(PrintaBunchaButtons) 소스.

UIElement에서 파생된 클래스 인스턴스를 인쇄할 때 중요한 단계가 필요하며, 엘리먼트를 배치하기 위해 객체의 Measure와 Arrange 메소드를 호출해야 한다.

Arrange 메소드 호출 후에 UIElement의 InvalidateArrange 메서드를 호출해야 인쇄 시 정상적으로 표시가 된다.

 

[PrintaBunchaButtons.cs 파일]

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace PrintaBunchaButtons
{
    public class PrintaBunchaButtons : Window
    {
        [STAThread]
        public static void Main()
        {
            Application app = new Application();
            app.Run(new PrintaBunchaButtons());
        }

        public PrintaBunchaButtons()
        {
            Title = "Print a Bunch of Buttons";
            SizeToContent = SizeToContent.WidthAndHeight;
            ResizeMode = ResizeMode.CanMinimize;

            //Print 버튼 생성
            Button btn = new Button();
            btn.FontSize = 24;
            btn.Content = "Print ...";
            btn.Padding = new Thickness(12);
            btn.Margin = new Thickness(96);
            btn.Click += PrintOnClick;
            Content = btn;
        }

        private void PrintOnClick(object sender, RoutedEventArgs e)
        {
            PrintDialog dlg = new PrintDialog();

            if ((bool)dlg.ShowDialog().GetValueOrDefault())
            {
                //그리드 패널 생성
                Grid grid = new Grid();

                //자동으로 크기가 변하는 열과 행을 5개 정의
                for (int i = 0; i < 5; i++)
                {
                    ColumnDefinition colDef = new ColumnDefinition();
                    colDef.Width = GridLength.Auto;
                    grid.ColumnDefinitions.Add(colDef);

                    RowDefinition rowDef = new RowDefinition();
                    rowDef.Height = GridLength.Auto;
                    grid.RowDefinitions.Add(rowDef);
                }

                //그라디언트 브러시로 그리드의 배경색을 지정
                grid.Background = new LinearGradientBrush(Colors.Gray, Colors.White, 
                                                          new Point(0, 0), new Point(1, 1));

                //난수 생성
                Random rand = new Random();

                //25개 버튼으로 Grid를 채움
                for (int i = 0; i < 25; i++)
                {
                    Button btn = new Button();
                    btn.FontSize = 12 + rand.Next(8);
                    btn.Content = "Button No. " + (i + 1);
                    btn.HorizontalAlignment = HorizontalAlignment.Center;
                    btn.VerticalAlignment = VerticalAlignment.Center;
                    btn.Margin = new Thickness(6);
                    grid.Children.Add(btn);
                    Grid.SetRow(btn, i % 5);
                    Grid.SetColumn(btn, i / 5);
                }

                //그리드 크기 결정
                grid.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

                Size sizeGrid = grid.DesiredSize;

                //페이지상의 그리드의 중앙점을 결정
                Point ptGrid = new Point((dlg.PrintableAreaWidth - sizeGrid.Width) / 2,
                                         (dlg.PrintableAreaHeight - sizeGrid.Height) / 2);

                //레이아웃은 설정하지 않고 통과
                grid.Arrange(new Rect(ptGrid, sizeGrid));
                grid.InvalidateArrange();
                //인쇄
                dlg.PrintVisual(grid, Title);
            }
        }
    }
}
반응형
반응형

찰스 페졸드의 WPF 를 읽으면서 정리한 인쇄(PrintWithMargins) 소스.

2개의 클래스 파일을 작성했으며, PrintWithMargins.cs 와 PageMarginsDialog.cs 파일로 구성된다.

 

[PrintWithMargins.cs 파일]

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace PrintWithMargins
{
    public class PageMarginsDialog : Window
    {
        //종이 테두리를 참조하는 내부 열거형
        enum Side
        {
            Left, Right, Top, Bottom
        }

        //숫자 입력을 위한 텍스트 박스 4개
        TextBox[] txtBox = new TextBox[4];
        Button btnOk;

        //페이지 여백을 위한 타입 Thickness의 Public 프로퍼티
        public Thickness PageMargins
        {
            set
            {
                txtBox[(int)Side.Left].Text = (value.Left / 96).ToString("F3");
                txtBox[(int)Side.Right].Text = (value.Right / 96).ToString("F3");
                txtBox[(int)Side.Top].Text = (value.Top / 96).ToString("F3");
                txtBox[(int)Side.Bottom].Text = (value.Bottom / 96).ToString("F3");
            }
            get
            {
                return new Thickness(Double.Parse(txtBox[(int) Side.Left].Text) * 96,
                                    Double.Parse(txtBox[(int)Side.Right].Text) * 96,
                                    Double.Parse(txtBox[(int)Side.Top].Text) * 96,
                                    Double.Parse(txtBox[(int)Side.Bottom].Text) * 96);
            }
        }

        //생성자
        public PageMarginsDialog()
        {
            //대화상자를 위한 표준 설정
            Title = "Page Setup";
            ShowInTaskbar = false;
            WindowStyle = WindowStyle.ToolWindow;
            WindowStartupLocation = WindowStartupLocation.CenterOwner;
            SizeToContent = SizeToContent.WidthAndHeight;
            ResizeMode = ResizeMode.NoResize;

            //윈도우 Content를 위한 스택 패널을 만든다.
            StackPanel stack = new StackPanel();
            Content = stack;

            //스택 패널의 자식으로 그룹 박스를 생성
            GroupBox grpBox = new GroupBox();
            grpBox.Header = "Margins (inches)";
            grpBox.Margin = new Thickness(12);
            stack.Children.Add(grpBox);

            //그룹 박스의 내용으로 그리드를 생성
            Grid grid = new Grid();
            grid.Margin = new Thickness(6);
            grpBox.Content = grid;

            //2개의 행과 4개의 열
            for (int i = 0; i < 2; i++)
            {
                RowDefinition rowDef = new RowDefinition();
                rowDef.Height = GridLength.Auto;
                grid.RowDefinitions.Add(rowDef);
            }

            for (int i = 0; i < 4; i++)
            {
                ColumnDefinition colDef = new ColumnDefinition();
                colDef.Width = GridLength.Auto;
                grid.ColumnDefinitions.Add(colDef);
            }

            //그리드에 레이블과 텍스트 박스 컨트롤을 추가
            for (int i = 0; i < 4; i++)
            {
                Label lbl = new Label();
                lbl.Content = "_" + Enum.GetName(typeof(Side), i) + ":";
                lbl.Margin = new Thickness(6);
                lbl.VerticalAlignment = VerticalAlignment.Center;
                grid.Children.Add(lbl);
                Grid.SetRow(lbl, i / 2);
                Grid.SetColumn(lbl, 2 * (i % 2));

                txtBox[i] = new TextBox();
                txtBox[i].TextChanged += TextBoxOnTextChanged;
                txtBox[i].MinWidth = 48;
                txtBox[i].Margin = new Thickness(6);
                grid.Children.Add(txtBox[i]);
                Grid.SetRow(txtBox[i], i / 2);
                Grid.SetColumn(txtBox[i], 2 * (i % 2) + 1);
            }

            //OK와 Cancel 버튼을 위해 UniformGrid를 이용
            UniformGrid uniGrid = new UniformGrid();
            uniGrid.Rows = 1;
            uniGrid.Columns = 2;
            stack.Children.Add(uniGrid);

            btnOk = new Button();
            btnOk.Content = "OK";
            btnOk.IsDefault = true;
            btnOk.IsEnabled = false;
            btnOk.MinWidth = 60;
            btnOk.Margin = new Thickness(12);
            btnOk.HorizontalAlignment = HorizontalAlignment.Center;
            btnOk.Click += OkButtonOnClick;
            uniGrid.Children.Add(btnOk);

            Button btnCancel = new Button();
            btnCancel.Content = "Cancel";
            btnCancel.IsCancel = true;
            btnCancel.MinWidth = 60;
            btnCancel.Margin = new Thickness(12);
            btnCancel.HorizontalAlignment = HorizontalAlignment.Center;
            uniGrid.Children.Add(btnCancel);
        }
        /// <summary>
        /// OK를 클릭하면 대화상자를 종료함
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OkButtonOnClick(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
        }
        /// <summary>
        /// 텍스트 박스의 값이 숫자이면 OK 버튼을 활성화
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextBoxOnTextChanged(object sender, TextChangedEventArgs e)
        {
            double result;

            btnOk.IsEnabled = Double.TryParse(txtBox[(int)Side.Left].Text, out result) &&
                            Double.TryParse(txtBox[(int)Side.Right].Text, out result) &&
                            Double.TryParse(txtBox[(int)Side.Top].Text, out result) &&
                            Double.TryParse(txtBox[(int)Side.Bottom].Text, out result);
        }
    }
}

 

 

[PageMarginsDialog.cs 파일]

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Printing;

namespace PrintWithMargins
{
    public class PrintWithMargins : Window
    {
        //PringDialog의 정보를 저장하기 위한 Private 필드
        PrintQueue prnQueue;
        PrintTicket prnTkt;
        Thickness marginPage = new Thickness(96);

        [STAThread]
        public static void Main()
        {
            Application app = new Application();
            app.Run(new PrintWithMargins());
        }

        public PrintWithMargins()
        {
            Title = "Print with Margins";
            FontSize = 24;

            //윈도우 Content를 위한 스택 패널 생성
            StackPanel stack = new StackPanel();
            Content = stack;

            //페이지 설정 버튼 생성
            Button btn = new Button();
            btn.Content = "Page Set_up...";
            btn.HorizontalAlignment = HorizontalAlignment.Center;
            btn.Margin = new Thickness(24);
            btn.Click += SetupOnClick;
            stack.Children.Add(btn);

            //인쇄 버튼 생성
            btn = new Button();
            btn.Content = "_Print...";
            btn.HorizontalAlignment = HorizontalAlignment.Center;
            btn.Margin = new Thickness(24);
            btn.Click += PrintOnClick;
            stack.Children.Add(btn);
        }
        /// <summary>
        /// 인쇄 버튼 : PringDialog 실행
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PrintOnClick(object sender, RoutedEventArgs e)
        {
            PrintDialog dlg = new PrintDialog();

            //PrintQueue와 PrintTicket 설정
            if (prnQueue != null) dlg.PrintQueue = prnQueue;

            if (prnTkt != null) dlg.PrintTicket = prnTkt;

            if (dlg.ShowDialog().GetValueOrDefault())
            {
                //PrintQueue와 PrintTicket을 대화상자의 값으로 설정
                prnQueue = dlg.PrintQueue;
                prnTkt = dlg.PrintTicket;

                //DrawingVisual을 생성하고 DrawingContext를 염
                DrawingVisual vis = new DrawingVisual();
                DrawingContext dc = vis.RenderOpen();
                Pen pen = new Pen(Brushes.Black, 1);

                //Rectangle은 여백을 뺀 페이지를 나타냄
                Rect rectPage = new Rect(marginPage.Left, marginPage.Top, 
                                         dlg.PrintableAreaWidth - (marginPage.Left + marginPage.Right), 
                                         dlg.PrintableAreaHeight - (marginPage.Top + marginPage.Bottom));

                //사용자 여백을 반영한 사각형 출력
                dc.DrawRectangle(null, pen, rectPage);

                //PrintableArea 프로퍼티를 보여주는 포맷팅된 텍스트 객체를 생성
                FormattedText formattedText = new FormattedText(String.Format("Hello, Printer! {0} x {1}",
                                                                dlg.PrintableAreaWidth / 96, dlg.PrintableAreaHeight / 96),
                                                                CultureInfo.CurrentCulture,
                                                                FlowDirection.LeftToRight,
                                                                new Typeface(new FontFamily("Times New Roman"), 
                                                                                FontStyles.Italic, FontWeights.Normal, FontStretches.Normal),
                                                                48, Brushes.Black);

                //포맷된 텍스트 스트링의 물리적 크기를 계산
                Size sizeText = new Size(formattedText.Width, formattedText.Height);

                //여백 내의 텍스트의 중앙점을 계산
                Point ptText = new Point(rectPage.Left + (rectPage.Width - formattedText.Width) / 2, 
                                         rectPage.Top + (rectPage.Height - formattedText.Height) / 2);

                //텍스트와 이를 둘러싸는 사각형 출력
                dc.DrawText(formattedText, ptText);
                dc.DrawRectangle(null, pen, new Rect(ptText, sizeText));

                //DrawingContext를 종료
                dc.Close();

                //끝으로 페이지를 인쇄
                dlg.PrintVisual(vis, Title);
            }
        }
        /// <summary>
        /// 페이지 설정 버튼 : PageMarginsDialog 실행
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SetupOnClick(object sender, RoutedEventArgs e)
        {
            //대화상자를 생성하고 PageMargins 프로퍼티를 초기화
            PageMarginsDialog dlg = new PageMarginsDialog();
            dlg.Owner = this;
            dlg.PageMargins = marginPage;

            if (dlg.ShowDialog().GetValueOrDefault())
            {
                //대화상자의 페이지 여백을 저장
                marginPage = dlg.PageMargins;
            }
        }
    }
}

 

 

 

반응형
반응형

찰스 페졸드의 WPF 를 읽으면서 정리한 인쇄(PrintEllipse) 소스.

책을 읽으면서 직접 코딩을 하면서 정리했던 소스들을 그대로 옮겨 보았다.

 

using System;
using System.Printing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace PrintEllipse
{
    public class PrintEllipse : Window
    {
        private PrintTicket prntkt;

        [STAThread]
        public static void Main()
        {
            Application app = new Application();
            app.Run(new PrintEllipse());
        }

        public PrintEllipse()
        {
            Title = "Print Ellipse";
            FontSize = 24;

            //윈도우 Content를 위한 스택 패널 생성
            StackPanel stack = new StackPanel();
            Content = stack;

            //인쇄를 위한 버튼 생성
            Button btn = new Button();
            btn.Content = "_Print...";
            btn.HorizontalAlignment = HorizontalAlignment.Center;
            btn.Margin = new Thickness(24);
            btn.Click += PrintOnClick;
            stack.Children.Add(btn);
        }

        private void PrintOnClick(object sender, RoutedEventArgs e)
        {
            PrintDialog dlg = new PrintDialog();
            if (prntkt != null) dlg.PrintTicket = prntkt;

            //페이지지정 라디오버튼을 활성화하기 위해서는 UserPageRangeEnabled를 true로 해야 한다.
            dlg.UserPageRangeEnabled = true;

            //ShowDialog는 널 값이 가능한 bool을 반환하게 정의되어 있다. 대화상자 클래스의 ShowDialog 메소드는 true/false/null을 반환한다.
            //사용자가 인쇄 버튼을 클릭하면 true를, 취소 버튼을 클릭하면 false를, 제목 옆의 닫기 버튼을 클릭하면 null을 반환한다.
            //GetValueOrDefault 메소드는 if문을 위해 결과가 항상 bool 형태가 되게 null 값을 false로 바꾸어 준다.
            if ((bool)dlg.ShowDialog().GetValueOrDefault())
            {
                prntkt = dlg.PrintTicket;

                //DrawingVisual을 생성하고 DrawingContext를 준비
                DrawingVisual vis = new DrawingVisual();
                DrawingContext dc = vis.RenderOpen();

                //타원을 출력
                //PrintableAreaWidth와 PrintableAreaHeight는 페이지의 인쇄 가능 영역을 참조하는 것이 아니라 장치 독립적인 단위(1/96)로 페이지의 전체 물리적인 크기를 가리킨다.
                dc.DrawEllipse(Brushes.LightGray, new Pen(Brushes.Black, 3),
                                new Point(dlg.PrintableAreaWidth / 2, dlg.PrintableAreaHeight / 2),
                                dlg.PrintableAreaWidth / 2 - 10, dlg.PrintableAreaHeight / 2 - 10);

                //DrawingCOntext를 닫음
                dc.Close();

                //끝으로 페이지를 인쇄
                dlg.PrintVisual(vis, "My First Print Job");
            }
        }
    }
}
반응형

+ Recent posts