Jak wydrukować zawartość WebView w aplikacji Windows Store?

Mam aplikację Metro i próbuję wydrukować zawartość kontrolki WebView. Używając próbki wydruku MSDN jako źródła odniesienia. Po prostu zmieniam XAML w printableArea w następujący sposób:

    <RichTextBlock>
        <Paragraph>
            <InlineUIContainer>
                <WebView Width="800" Height="2000" Source="http://www.stackoverflow.com"/>
            </InlineUIContainer>
        </Paragraph>
    </RichTextBlock>
To działa częściowo. Problem polega na tym, że obszar Visible w określonych wymiarach jest drukowany, tzn. obszar, który można przewijać, nie jest drukowany, a także nie jest wyświetlany jako wiele stron w PrintPreview .

I ' m prawie tam, doceniłbym trochę pomocy, aby to działało zgodnie z oczekiwaniami.

Nie znalazłem nigdzie żadnych próbek, które rozwiązują ten konkretny problem.

Próbowałem nawet rozwiązań tutaj: http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/5edcb239-7a5b-49f7-87e3-e5a253b809c4

Nie jestem pierwszym, który doświadczył tego samego / podobnego problem: http://social.msdn.microsoft.com/Search/en-US/?Refinement=112&query=print%20webview#refinementChanges=180&pageNumber=1&showMore=false

Chętny dać każdemu, kto może rozwiązać ten problem 100 punkt bounty. Byłbym wdzięczny za przejście, przykładowy kod lub przykładowy projekt jako rozwiązanie.

Author: Jerry Nixon, 2013-06-11

2 answers

Jasne, proszę.

Najpierw możesz zmienić rozmiar WebView na rzeczywistą zawartość. Następnie skalujesz WebView z powrotem do oryginalnego rozmiaru. Wymagałoby wywołania skryptu i ScaleTransform. Całkiem proste, naprawdę.

Tak:

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

To spowoduje bardzo wysoki, wąski WebView Jak to:

Tutaj wpisz opis obrazka

Ale nie tego chcesz.

Nawet jeśli można zmienić rozmiar prostokąta tak, aby nie był tak szalony kształt, Wydruk Umowa w systemie Windows 8 wymaga podania jednej strony. To nie robi paginacji za Ciebie. W rezultacie, to, czego naprawdę potrzebujesz, to odzyskać indywidualną stronę internetową, po jednej stronie na raz.

Pierwsze podejście jest podstawą tego, jak to zrobić. Ale musisz naprawić rozmiar prostokąta do rozmiaru strony przekazanego ci przez zadanie drukowania w systemie Windows 8. Będzie to oparte na wyborze drukarki użytkownika. Na przykład List kontra A4 (w Wielkiej Brytanii). Następnie, korzystając z właściwości Stretch szczotka, którą możesz zapewnić, że sama się zacina. Następnie, korzystając z właściwości Przekształć pędzel, możesz przesuwać go w górę iw dół wewnątrz prostokąta, aż odsłoni stronę, którą chcesz wydrukować.

Oto jak:

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

Więc UI będzie coś takiego, gdzie lewa kolumna jest WebView, Druga kolumna (Środkowa) jest all-in-one, jak nasze pierwsze rozwiązanie, a trzeci, jest repeater pokazujący poszczególne strony gotowe do wydruku.

Tutaj wpisz opis obrazka

Z oczywiście magia jest naprawdę w metodzie GetWebPages ()! Nie mam nic przeciwko temu, że to prosty cud zrobiony całkiem łatwo przy okazji pracy C# i Transforms.

Proszę zauważyć, że jest toniekompletne . Tak, to rozbija stronę dla ciebie, ale nie mogę być pewien, ile marginesu chcesz na swojej stronie. Więc wymagane poprawki są małe, ale chciałem o tym wspomnieć. Jest to 98% kodu, który musisz rozbić Widok sieci Web i przygotować, jeśli dla zadania drukowania Windows 8 w odpowiedzi na paginate event. Następnie przekaż do niego prostokąty po kolei.

Powiedziawszy to, jest to prawdopodobnie najbardziej kompleksowe rozwiązanie tego problemu w Internecie. :)

Powodzenia!!
 30
Author: Jerry Nixon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-20 19:55:19

Oto podstawowa składnia drukowania.

PrintManager.PrintTaskRequested += printManager_PrintTaskRequested;
void printManager_PrintTaskRequested(
    Windows.Graphics.Printing.PrintManager sender,
    Windows.Graphics.Printing.PrintTaskRequestedEventArgs args)
    {
        ...
    }
 -1
Author: Jerry Nixon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-24 23:28:16