2013-06-11 5 views
16

Ich habe eine Metro App und ich versuche, den Inhalt einer WebView Kontrolle zu drucken. Verwenden Sie das MSDN Print Sample als meine Quellreferenz. Ich habe einfach den XAML im printableArea wie folgt ändern:Wie drucke ich WebView-Inhalte in einer Windows Store App?

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

Das funktioniert teilweise. Das Problem besteht darin, dass der Bereich Visible in den angegebenen Dimensionen Gedruckt ist, d. H. Der Bereich, der gescrollt werden kann, druckt nicht und wird nicht als mehrere Seiten in dem PrintPreview angezeigt.

Ich bin fast da, würde mich über ein wenig Hilfe freuen, damit dies wie erwartet funktioniert.

Ich habe nirgendwo Proben gefunden, die dieses spezifische Problem angehen.

Ich habe versucht, auch die Lösungen hier: http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/5edcb239-7a5b-49f7-87e3-e5a253b809c4

Ich bin nicht die erste gleiches/ähnliches Problem erlebt hat: http://social.msdn.microsoft.com/Search/en-US/?Refinement=112&query=print%20webview#refinementChanges=180&pageNumber=1&showMore=false

Willing jemanden zu geben, die dieses Problem in eine 100-Punkte-Prämie lösen . Ich würde gerne eine exemplarische Vorgehensweise, einen Beispielcode oder ein Scheinprojekt als Lösung begrüßen.

+0

Wie hoch ist der RichTextBlock? Ist es auf Clip eingestellt? Ich frage mich, ob es die Höhe des RTB/Absatzes anstelle des WebView druckt. –

Antwort

28

Sicher, hier gehst du.

Zuerst können Sie die Größe WebView auf den tatsächlichen Inhalt ändern. Dann skalieren Sie die WebView wieder auf die Originalgröße. Es würde einen Skriptaufruf und eine ScaleTransform erfordern. Ziemlich einfach, wirklich.

So:

<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; 
} 

dies in einer sehr hohen führt, schmal WebView wie folgt aus:

enter image description here

Aber das ist nicht das, was Sie wollen.

Auch wenn Sie das resultierende Rechteck so ändern können, dass es nicht so verrückt aussieht, müssen Sie für den Druckvertrag in Windows 8 eine einzelne Seite angeben. Es macht nicht die Paginierung für Sie. Als Ergebnis benötigen Sie wirklich die einzelne Website, eine Seite nach der anderen.

Der erste Ansatz ist die Grundlage dafür. Sie müssen jedoch die Größe des Rechtecks ​​an die Seitengröße anpassen, die Ihnen von der Windows 8-Aufgabe Drucken übergeben wird. Dies basiert auf der Druckerauswahl des Benutzers. Zum Beispiel Brief im Vergleich zu A4 (in Großbritannien). Mit der Eigenschaft "Dehnung" des Pinsels können Sie sicherstellen, dass sie sich selbst abschneidet. Anschließend können Sie die Eigenschaft Transformieren des Pinsels verwenden, um sie innerhalb des Rechtecks ​​nach oben und unten zu verschieben, bis die zu druckende Seite angezeigt wird.

Hier ist, wie:

<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; 
} 

So ist die Benutzeroberfläche so etwas wie dies sein wird, wo die linke Spalte die WebView ist, die zweite Spalte (Mitte) ist die All-in-one, wie unsere erste Lösung, und der dritte ist ein Repeater, der die einzelnen druckfertigen Seiten anzeigt.

enter image description here

Natürlich ist die Magie wirklich in den GetWebPages ist() -Methode! Es macht mir nichts aus zu sagen, es ist ein einfaches Wunder, das durch die Art und Weise, wie C# und Transforms funktionieren, ziemlich einfach gemacht wird.

Bitte beachten Sie, dies ist nicht vollständig. Ja, es bricht die Seite für dich auf, aber ich kann nicht sicher sein, wie viel Marge du auf deiner Seite haben willst. Die erforderlichen Feinabstimmungen sind also winzig, aber ich wollte es erwähnen. Das sind 98% des Codes, den Sie benötigen, um ein WebView zu zerlegen und für die Windows 8-Druckaufgabe als Antwort auf das Paginate-Ereignis vorzubereiten. Übergeben Sie dann die Rechtecke einzeln nacheinander.

Mit diesen Worten ist dies wahrscheinlich die umfassendste Lösung für dieses Problem im Internet. :)

Viel Glück !!

+1

Danke Herr Nixon !!! Ihre Vorschläge waren genau richtig. Ich habe Ihre Antwort aktualisiert, um den Code für die Ränder einzufügen. Tausend Dank. Du bist ein Lebensretter. Meine App ist jetzt bereit für den App Store :) – c0D3l0g1c

+1

Sehr glatt - am besten im Netz tatsächlich :) –

+0

Ich habe Schwierigkeiten, dies zu arbeiten - ich lade meinen Inhalt statisch mit 'NavigateToString'. Der Code funktioniert für eine Datei von ungefähr 4000 Wörtern, aber wenn ich das ein wenig aufstelle, hört es auf zu arbeiten. Die WebView schrumpft, das ItemsControl ist leer und nach ca. 4 Sekunden wird der Bildschirm grau. Keine Ausnahmen oder Fehler. Irgendwelche Ideen? – roryok

0

Hier ist die grundlegende Druck-Syntax.

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