2013-06-11 8 views
16

Ho una Metro App e sto tentando di stampare il contenuto di un controllo WebView. Utilizzo del campione di stampa MSDN come riferimento di origine. Ho semplicemente cambiare il XAML nel printableArea come segue:Come si stampa il contenuto WebView in un'app di Windows Store?

<RichTextBlock> 
     <Paragraph> 
      <InlineUIContainer> 
       <WebView Width="800" Height="2000" Source="http://www.stackoverflow.com"/> 
      </InlineUIContainer> 
     </Paragraph> 
    </RichTextBlock> 

Questo funziona parzialmente. Il problema è che l'area Visible nelle dimensioni specificate viene stampata, ad esempio L'area che può essere spostata non stampa e anche non viene visualizzata come più pagine in PrintPreview.

Sono quasi arrivato, apprezzerei un po 'di aiuto per farlo funzionare come previsto.

Non ho trovato alcun campione da nessuna parte, che risolva questo problema specifico.

ho anche provato le soluzioni qui: http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/5edcb239-7a5b-49f7-87e3-e5a253b809c4

io non sono il primo ad aver sperimentato lo stesso problema/simile: http://social.msdn.microsoft.com/Search/en-US/?Refinement=112&query=print%20webview#refinementChanges=180&pageNumber=1&showMore=false

Disposti a dare a nessuno che può risolvere questo problema una taglia di 100 punti . Gradirei una soluzione, un codice di esempio o un progetto di simulazione.

+0

Qual è l'altezza di RichTextBlock? È impostato per tagliare? Mi chiedo se sta stampando l'altezza della RTB/Paragrafo invece di WebView. –

risposta

28

Certo, ecco qua.

Innanzitutto, è possibile ridimensionare lo WebView nel contenuto effettivo. Quindi, ridimensiona lo WebView nella dimensione originale. Richiederebbe un richiamo di script e un ScaleTransform. Abbastanza semplice, davvero.

Ti piace questa:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> 
    <WebView x:Name="MyWebView" Source="http://www.stackoverflow.com" /> 
</Grid> 

void MyWebView_LoadCompleted(object sender, NavigationEventArgs e) 
{ 
    var _Original = MyWebView.RenderSize; 

    // ask the content its width 
    var _WidthString = MyWebView.InvokeScript("eval", 
     new[] { "document.body.scrollWidth.toString()" }); 
    int _Width; 
    if (!int.TryParse(_WidthString, out _Width)) 
     throw new Exception(string.Format("failure/width:{0}", _WidthString)); 

    // ask the content its height 
    var _HeightString = MyWebView.InvokeScript("eval", 
     new[] { "document.body.scrollHeight.toString()" }); 
    int _Height; 
    if (!int.TryParse(_HeightString, out _Height)) 
     throw new Exception(string.Format("failure/height:{0}", _HeightString)); 

    // resize the webview to the content 
    MyWebView.Width = _Width; 
    MyWebView.Height = _Height; 

    // scale the webview back to original height (can't do both height & width) 
    var _Transform = (MyWebView.RenderTransform as ScaleTransform) 
     ?? (MyWebView.RenderTransform = new ScaleTransform()) as ScaleTransform; 
    var _Scale = _Original.Height/_Height; 
    _Transform.ScaleX = _Transform.ScaleY = _Scale; 
} 

Questo si tradurrà in un molto alto e stretto WebView come questo:

enter image description here

Ma non è questo ciò che si desidera.

Anche se è possibile ridimensionare il rettangolo risultante in modo che non sia a forma di pazzo, il contratto di stampa in Windows 8 richiede di fornire una singola pagina. Non fa l'impaginazione per te. Di conseguenza, ciò di cui hai realmente bisogno è di recuperare il singolo sito Web, una pagina alla volta.

Il primo approccio è la base su come farlo. Ma hai bisogno di aggiustare la dimensione del rettangolo alle dimensioni della pagina che ti sono state passate dall'attività Stampa di Windows 8. Questo sarà basato sulla selezione della stampante dell'utente. Ad esempio, Lettera contro A4 (nel Regno Unito). Quindi, usando la proprietà Stretch del pennello, puoi assicurarti che si ritiri da solo. Quindi, usando la proprietà Transform del pennello, è possibile farlo scorrere su e giù all'interno del rettangolo fino a quando non viene rivelata la pagina che si desidera stampare.

Ecco come:

<Grid Background="Blue"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="995" /> 
     <ColumnDefinition Width="300" /> 
     <ColumnDefinition /> 
    </Grid.ColumnDefinitions> 
    <WebView Grid.Column="0" x:Name="MyWebView" Source="http://www.stackoverflow.com" HorizontalAlignment="Right" /> 
    <Rectangle Grid.Column="1" x:Name="MyWebViewRectangle" Fill="Red" /> 
    <ScrollViewer Grid.Column="2" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> 
     <ItemsControl x:Name="MyPrintPages" VerticalAlignment="Top" HorizontalAlignment="Left"> 
      <Rectangle Height="150" Width="100" Fill="White" Margin="5" /> 
      <Rectangle Height="150" Width="100" Fill="White" Margin="5" /> 
      <Rectangle Height="150" Width="100" Fill="White" Margin="5" /> 
      <Rectangle Height="150" Width="100" Fill="White" Margin="5" /> 
      <Rectangle Height="150" Width="100" Fill="White" Margin="5" /> 
     </ItemsControl> 
    </ScrollViewer> 
</Grid> 

public MainPage() 
{ 
    this.InitializeComponent(); 
    MyWebView.LoadCompleted += MyWebView_LoadCompleted; 
} 

void MyWebView_LoadCompleted(object sender, NavigationEventArgs e) 
{ 
    MyWebViewRectangle.Fill = GetWebViewBrush(MyWebView); 
    MyPrintPages.ItemsSource = GetWebPages(MyWebView, new Windows.Foundation.Size(100d, 150d)); 
    MyWebView.Visibility = Windows.UI.Xaml.Visibility.Visible; 
} 

WebViewBrush GetWebViewBrush(WebView webView) 
{ 
    // resize width to content 
    var _OriginalWidth = webView.Width; 
    var _WidthString = webView.InvokeScript("eval", 
     new[] { "document.body.scrollWidth.toString()" }); 
    int _ContentWidth; 
    if (!int.TryParse(_WidthString, out _ContentWidth)) 
     throw new Exception(string.Format("failure/width:{0}", _WidthString)); 
    webView.Width = _ContentWidth; 

    // resize height to content 
    var _OriginalHeight = webView.Height; 
    var _HeightString = webView.InvokeScript("eval", 
     new[] { "document.body.scrollHeight.toString()" }); 
    int _ContentHeight; 
    if (!int.TryParse(_HeightString, out _ContentHeight)) 
     throw new Exception(string.Format("failure/height:{0}", _HeightString)); 
    webView.Height = _ContentHeight; 

    // create brush 
    var _OriginalVisibilty = webView.Visibility; 
    webView.Visibility = Windows.UI.Xaml.Visibility.Visible; 
    var _Brush = new WebViewBrush 
    { 
     SourceName = webView.Name, 
     Stretch = Stretch.Uniform 
    }; 
    _Brush.Redraw(); 

    // reset, return 
    webView.Width = _OriginalWidth; 
    webView.Height = _OriginalHeight; 
    webView.Visibility = _OriginalVisibilty; 
    return _Brush; 
} 

IEnumerable<FrameworkElement> GetWebPages(WebView webView, Windows.Foundation.Size page) 
{ 
    // ask the content its width 
    var _WidthString = webView.InvokeScript("eval", 
     new[] { "document.body.scrollWidth.toString()" }); 
    int _ContentWidth; 
    if (!int.TryParse(_WidthString, out _ContentWidth)) 
     throw new Exception(string.Format("failure/width:{0}", _WidthString)); 
    webView.Width = _ContentWidth; 

    // ask the content its height 
    var _HeightString = webView.InvokeScript("eval", 
     new[] { "document.body.scrollHeight.toString()" }); 
    int _ContentHeight; 
    if (!int.TryParse(_HeightString, out _ContentHeight)) 
     throw new Exception(string.Format("failure/height:{0}", _HeightString)); 
    webView.Height = _ContentHeight; 

    // how many pages will there be? 
    var _Scale = page.Width/_ContentWidth; 
    var _ScaledHeight = (_ContentHeight * _Scale); 
    var _PageCount = (double)_ScaledHeight/page.Height; 
    _PageCount = _PageCount + ((_PageCount > (int)_PageCount) ? 1 : 0); 

    // create the pages 
    var _Pages = new List<Windows.UI.Xaml.Shapes.Rectangle>(); 
    for (int i = 0; i < (int)_PageCount; i++) 
    { 
     var _TranslateY = -page.Height * i; 
     var _Page = new Windows.UI.Xaml.Shapes.Rectangle 
     { 
      Height = page.Height, 
      Width = page.Width, 
      Margin = new Thickness(5), 
      Tag = new TranslateTransform { Y = _TranslateY }, 
     }; 
     _Page.Loaded += (s, e) => 
     { 
      var _Rectangle = s as Windows.UI.Xaml.Shapes.Rectangle; 
      var _Brush = GetWebViewBrush(webView); 
      _Brush.Stretch = Stretch.UniformToFill; 
      _Brush.AlignmentY = AlignmentY.Top; 
      _Brush.Transform = _Rectangle.Tag as TranslateTransform; 
      _Rectangle.Fill = _Brush; 
     }; 
     _Pages.Add(_Page); 
    } 
    return _Pages; 
} 

Così l'interfaccia utente sarà qualcosa come questo, dove la colonna di sinistra è il WebView, la seconda colonna (al centro) è l'all-in-one come la nostra prima soluzione, e il terzo è un ripetitore che mostra le singole pagine pronte per la stampa.

enter image description here

Naturalmente la magia è davvero nei GetWebPages metodo()! Non mi dispiace dire che è una semplice meraviglia resa abbastanza semplice dal modo in cui funzionano C# e Transforms.

Si prega di notare, questo è non completo. Sì, rompe la pagina per te, ma non posso essere sicuro di quanto margine vuoi sulla tua pagina. Quindi il tweaking richiesto è minuscolo, ma volevo menzionarlo. Questo è il 98% del codice necessario per interrompere una visualizzazione Web e la preparazione se per l'attività di stampa di Windows 8 in risposta per l'evento impaginato. Quindi passa i rettangoli ad esso uno alla volta.

Detto questo, questa è probabilmente la soluzione più completa per questo problema su Internet. :)

Buona fortuna !!

+1

Grazie signor Nixon !!! I tuoi suggerimenti erano esatti. Ho aggiornato la tua risposta per includere il codice per i margini. Grazie mille. Sei un risparmiatore di vita. La mia app è ora pronta per l'app store :) – c0D3l0g1c

+1

Very slick - il migliore in rete in effetti :) –

+0

Ho difficoltà a farlo funzionare - Carico i miei contenuti staticamente usando 'NavigateToString'. Il codice funziona per un file di circa 4000 parole, ma se lo spoglio un po 'smette di funzionare. La WebView si restringe, ItemsControl è vuoto e dopo circa 4 secondi lo schermo diventa grigio. Nessuna eccezione o errore. Qualche idea? – roryok

0

Ecco la sintassi di stampa di base.

PrintManager.PrintTaskRequested += printManager_PrintTaskRequested; 
void printManager_PrintTaskRequested(
    Windows.Graphics.Printing.PrintManager sender, 
    Windows.Graphics.Printing.PrintTaskRequestedEventArgs args) 
    { 
     ... 
    } 
Problemi correlati