2017-10-01 1 views
0

this을 기반으로하는 일반 MVVM 프레임 워크를 사용하여 WPF로 만든 응용 프로그램을 만들었습니다. 워크 플로우가 끝나면 PDF로 인쇄해야하는 정보가 오래 있습니다. 가장 쉬운 방법으로 XPS에 인쇄합니다.MVVM을 사용하여 WPF에서 XPS보기

here과 같이 FlowDocument를 사용하여 수정할 수있는 페이지 매김에 문제가 있음을 발견했습니다.

내 현재 문제는 ... 뷰에 모든 정보가 있고이 뷰가 MVVM이기 때문에 직접 액세스하지 않으면 모든 뷰가 포함 된 뷰의 인스턴스에 어떻게 액세스합니까? 정보를 추출하여 FlowDocument에 공급합니까? 뷰 모델 인스턴스에서 뷰의 현재 인스턴스를 읽으려면 어떻게해야합니까?

간단히 말해서, 저는 기본적으로 <Grid> ... </Grid>의 인스턴스를 어린이 및 실제 텍스트 등으로 읽으려고합니다. 앱에 표시된대로 ... 이걸 FlowDocument ...에 전달하지만 어떻게 할 수 있습니까? 보기 모델에서?

답변

0

보기를 읽지 않으려 고합니다. 너무 복잡합니다.

보기 구성 요소에는 두 개의 부모가있을 수 없습니다.

나는 (더 많은) UserControl을 XPS에 포함시켜야한다고 생각합니다.

은 그 때 나는 DataContext에 같은 뷰 모델을 제공하는 FlowDocument에서 같은 UserControl을을 실체화 할

감사

난 당신이 문서를 인쇄하기 위해 시각적 객체를 사용할 필요가 없습니다 것이라고 상상
+0

안녕하세요, 이것은 좋은 옵션처럼 보입니다 ... 내보기는 사용자 컨트롤이지만 루트보기에서 직접 datatemplate을 사용하여 인스턴스화되고보기 모델에서 그런 식으로 액세스됩니다. '그러면 뷰 모델에서 뷰 바인딩에 액세스하기 만하면됩니다. 다른 방법으로 (XAML보다는 코드로)보기를 인스턴스화하기 위해 다른 설정이 필요하다는 것을 의미합니다. – gbdavid

+0

희망 좋은 선택입니다 ;-). 저는보기가 시작되는 방식이 정말로 중요하다고 생각하지 않습니다. 그러나 ViewModel은 동일해야합니다. –

0

. 주로 최종 사용자가 문서를 인쇄 할 때 사용할 페이지 크기 나 방향이 아닐 수도 있기 때문입니다.

다음은 책에서 얻은 기본 인쇄 관리자입니다.이 기본 개념에서 인쇄 요구 사항을 모두 관리했습니다.

using System.IO; 
using System.Printing; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Media; 

namespace MyTextEditor 
{ 
    public class PrintManager 
    { 
     public static readonly int DPI = 96; 
     private readonly RichTextBox _textBox; 

     public PrintManager(RichTextBox textBox) 
     { 
      _textBox = textBox; 
     } 

     public bool Print() 
     { 

      PrintDialog dlg = new PrintDialog(); 

      if (dlg.ShowDialog() == true) 
      { 

       PrintQueue printQueue = dlg.PrintQueue; 
       DocumentPaginator paginator = GetPaginator(
        printQueue.UserPrintTicket.PageMediaSize.Width.Value, 
        printQueue.UserPrintTicket.PageMediaSize.Height.Value); 

       dlg.PrintDocument(paginator, "TextEditor Printing"); 

       return true; 
      } 

      return false; 
     } 

     public DocumentPaginator GetPaginator(
      double pageWidth, 
      double pageHeight) 
     { 
      TextRange originalRange = new TextRange(
       _textBox.Document.ContentStart, 
       _textBox.Document.ContentEnd); 

      MemoryStream memoryStream = new MemoryStream(); 
      originalRange.Save(memoryStream, DataFormats.Xaml); 

      FlowDocument copy = new FlowDocument(); 

      TextRange copyRange = new TextRange(
       copy.ContentStart, 
       copy.ContentEnd 
       ); 

      copyRange.Load(memoryStream, DataFormats.Xaml); 

      DocumentPaginator paginator = ((IDocumentPaginatorSource)copy).DocumentPaginator; 

      return new PrintingPaginator(
       paginator, 
       new Size(
        pageWidth, 
        pageHeight), 
        new Size(
         DPI, 
         DPI)); 



     } 

     public void PrintPreview() 
     { 
      PrintPreviewDialog dlg = new PrintPreviewDialog(this); 
      dlg.ShowDialog(); 
     } 
    } 
} 

/// <summary> 
/// This custom paginator wraps the original and adds some additional 
/// functionality. Notice that many of the properties pass through to 
/// the orginal. The constructor begins by setting the original's page 
/// size to a size reflected by the requested size and margins and then 
/// asks the underlying paginator to figure out how many pages we have. 
/// 
/// The next function worth noting is the overide method GetPage. WPF 
/// calls this method each time it requires a page for display or print. 
/// </summary> 
public class PrintingPaginator : DocumentPaginator 
{ 

    private readonly DocumentPaginator _originalPaginator; 
    private readonly Size _pageSize; 
    private readonly Size _pageMargin; 

    public PrintingPaginator(DocumentPaginator paginator, 
           Size pageSize, 
           Size margin) 
    { 
     _originalPaginator = paginator; 
     _pageSize = pageSize; 
     _pageMargin = margin; 


     _originalPaginator.PageSize = new Size(
      _pageSize.Width - _pageMargin.Width * 2, 
      _pageSize.Height - _pageMargin.Height * 2); 

     _originalPaginator.ComputePageCount(); 
    } 


    public override bool IsPageCountValid 
    { 
     get 
     { 
      return _originalPaginator.IsPageCountValid; 
     } 
    } 

    public override int PageCount 
    { 
     get 
     { 
      return _originalPaginator.PageCount; 
     } 
    } 

    public override Size PageSize 
    { 
     get 
     { 
      return _originalPaginator.PageSize; 
     } 
     set 
     { 
      _originalPaginator.PageSize = value; 
     } 
    } 

    public override IDocumentPaginatorSource Source 
    { 
     get 
     { 
      return _originalPaginator.Source; 
     } 
    } 


    /// <summary> 
    /// GetPage 
    /// 1. Obtain the original page form the original paginator 
    /// 2. Wrap the page in a ContainerVisual, to make it easier manipulate. 
    /// 3. Use a TranslateTransform to move the contents fo the ContainerVisual in line with the margins 
    /// 4. Returns a new page object with its content and bleed adjusted in line with the margins 
    /// </summary> 
    /// <param name="pageNumber"> 
    /// Specifies the page number to be return by GetPage 
    /// </param> 
    /// <returns></returns> 
    public override DocumentPage GetPage(int pageNumber) 
    { 
     DocumentPage originalPage = _originalPaginator.GetPage(pageNumber); 
     ContainerVisual fixedPage = new ContainerVisual(); 

     fixedPage.Children.Add(originalPage.Visual); 

     fixedPage.Transform = new TranslateTransform(
      _pageMargin.Width, 
      _pageMargin.Height); 

     return new DocumentPage(
          fixedPage, 
          _pageSize, 
          AdjustForMargins(originalPage.BleedBox), 
          AdjustForMargins(originalPage.ContentBox) 
          ); 

    } 

    private Rect AdjustForMargins(Rect rect) 
    { 
     if (rect.IsEmpty) return rect; 
     else 
     { 
      return new Rect(
          rect.Left + _pageMargin.Width, 
          rect.Top + _pageMargin.Height, 
          rect.Width, 
          rect.Height); 
     } 
    } 



} 
관련 문제