How to wait for WebViewBrush.Redraw () to finish (UWP printing)?

I have a basic UWP application with a built-in WebView representing a fairly large HTML document (up to 500 printed pages with letter size).

I want to add support for printing this HTML document. Here is my approach:

  • To support pagination, I generate a second HTML document, paginated, using <div style="height:100vh">up to 500 of them for each "page".
  • I load this paginated HTML into a second, hidden WebViewon a XAML page, which I resize to fit exactly one page based on the user selected page size.
  • I'm waiting for WebView to complete the download ...
  • Now for each "page":
    • I set WebView scrollYto display only the current page using JavaScript:window.scrollTo(0, -pageOffset)
    • Then I use WebViewBrushto create a snapshot of the current page inWebView
    • Repeat this for all remaining pages ...

Problem:

I can create a print preview on all 500 pages, but sometimes there are no pages on the print preview, while other pages appear several times.

I suspect this is because I use a WebViewBrush.Redraw()scrolled WebView to capture the snapshot, but the documentation says what Redraw() happens asynchronously . I can scroll the previous page before WebViewBrush gets the ability to redraw, and then accidentally grabs the next page.

, WebViewBrush WebView, ?

:

    private async Task<Rectangle> MakePage(WebView webView, 
                        Size pageSize, double pageOffset)
    {
        // Scroll to next page:
        await webView.EvaluateJavaScriptSnippetAsync(
                             $"window.scrollTo(0, {pageOffset})");

        var brush = new WebViewBrush();
        brush.Stretch = Stretch.Uniform;
        brush.SetSource(webView);
        brush.Redraw(); // XXX Need to wait for this, but there no API

        // Add a delay hoping Redraw() finishes... I think here is the problem.
        await Task.Delay(150);

        var rectangle = new Rectangle()
        {
            Width = pageSize.Width,
            Height = pageSize.Height
        };

        rectangle.Fill = brush;
        brush.Stretch = Stretch.UniformToFill;
        brush.AlignmentY = AlignmentY.Top;

        return rectangle;
    }

. WebViewBrush 500 , . WebView , 200 .

BOUNTY: , 100 , , 500 .

+7
2

WebViewBrush :

WebView , , . WebViewBrush , XAML ( URI WebView). SetSource WebViewBrush , (, SetSource WebView.LoadCompleted.

SetSource WebViewBrush WebView.LoadCompleted.

+5

, , HTML-. , 500 . HTML-. , HTML- , .

-. UWP, .

, , , , , , 90% .

, . - . . . , ( :)), # . .

XAML

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

#

public MainPage()
{
    this.InitializeComponent();

    wv.LoadCompleted += Wv_LoadCompleted;
}

async private void Wv_LoadCompleted(object sender, NavigationEventArgs e)
{
    var allPages = await GetWebPages(wv, new Windows.Foundation.Size(100d, 150d));
}

async Task<IEnumerable<FrameworkElement>> GetWebPages(WebView webView, Windows.Foundation.Size pageSize)
{
    // GETTING WIDTH FROM WEVIEW CONTENT
    var widthFromView = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollWidth.toString()" });

    int contentWidth;
    if (!int.TryParse(widthFromView, out contentWidth))
        throw new Exception(string.Format("failure/width:{0}", widthFromView));
    webView.Width = contentWidth;

    // GETTING HEIGHT FROM WEBVIEW CONTENT
    var heightFromView = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight.toString()" });

    int contentHeight;
    if (!int.TryParse(heightFromView, out contentHeight))
        throw new Exception(string.Format("failure/height:{0}", heightFromView));

    webView.Height = contentHeight;

    // CALCULATING NO OF PAGES
    var scale = pageSize.Width / contentWidth;
    var scaledHeight = (contentHeight * scale);
    var pageCount = (double)scaledHeight / pageSize.Height;
    pageCount = pageCount + ((pageCount > (int)pageCount) ? 1 : 0);

    // CREATE PAGES
    var pages = new List<Windows.UI.Xaml.Shapes.Rectangle>();
    for (int i = 0; i < (int)pageCount; i++)
    {
        var translateY = -pageSize.Height * i;
        var page = new Windows.UI.Xaml.Shapes.Rectangle
        {
            Height = pageSize.Height,
            Width = pageSize.Width,
            Margin = new Thickness(5),
            Tag = new TranslateTransform { Y = translateY },
        };

        page.Loaded += async (s, e) =>
        {
            var rectangle = s as Windows.UI.Xaml.Shapes.Rectangle;
            var wvBrush = await GetWebViewBrush(webView);
            wvBrush.Stretch = Stretch.UniformToFill;
            wvBrush.AlignmentY = AlignmentY.Top;
            wvBrush.Transform = rectangle.Tag as TranslateTransform;
            rectangle.Fill = wvBrush;
        };

        pages.Add(page);
    }
    return pages;
}

async Task<WebViewBrush> GetWebViewBrush(WebView webView)
{
    // ASSING ORIGINAL CONTENT WIDTH
    var originalWidth = webView.Width;

    var widthFromView = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollWidth.toString()" });

    int contentWidth;
    if (!int.TryParse(widthFromView, out contentWidth))
        throw new Exception(string.Format("failure/width:{0}", widthFromView));
    webView.Width = contentWidth;

    // ASSINGING ORIGINAL CONTENT HEIGHT
    var originalHeight = webView.Height;

    var heightFromView = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight.toString()" });

    int contentHeight;
    if (!int.TryParse(heightFromView, out contentHeight))
        throw new Exception(string.Format("failure/height:{0}", heightFromView));
    webView.Height = contentHeight;

    // CREATING BRUSH
    var originalVisibilty = webView.Visibility;
    webView.Visibility = Windows.UI.Xaml.Visibility.Visible;

    var wvBrush = new WebViewBrush
    {
        SourceName = webView.Name,
        Stretch = Stretch.Uniform
    };
    wvBrush.Redraw();

    webView.Width = originalWidth;
    webView.Height = originalHeight;
    webView.Visibility = originalVisibilty;

    return wvBrush;
}
+3

All Articles