Как распечатать содержимое WebView в приложении Магазина Windows?

У меня есть приложение Metro, и я пытаюсь напечатать содержимое WebView контроль. Использование MSDN Print Sample в качестве моего источника ссылки. Я просто изменяю XAML в printableArea следующее:

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

Это работает частично. Проблема в том, что Visible Область в указанных размерах - "Печатная", т.е. область, которую можно прокрутить, не печатает, а также не отображается как "Несколько страниц" в PrintPreview.

Я почти там, был бы признателен за небольшую помощь, чтобы заставить это работать, как ожидалось.

Я нигде не нашел образцов, которые занимаются этой конкретной проблемой.

Я даже попробовал решения здесь: http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/5edcb239-7a5b-49f7-87e3-e5a253b809c4

Я не первый, кто столкнулся с такой же / похожей проблемой: http://social.msdn.microsoft.com/Search/en-US/?Refinement=112&query=print%20webview

Готов дать любому, кто может решить эту проблему, награду в 100 баллов. Был бы признателен пошаговое руководство, пример кода или макет проекта в качестве решения.

2 ответа

Решение

Конечно, держи.

Во-первых, вы можете изменить размер WebView к фактическому содержанию. Затем вы масштабируете WebView вернуться к исходному размеру. Это потребует вызова сценария и ScaleTransform, Довольно просто, правда.

Как это:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <WebView x:Name="MyWebView" Source="http://www.stackru.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;
}

Это приведет к очень высокой, узкой WebView как это:

введите описание изображения здесь

Но это не то, что вы хотите.

Несмотря на то, что вы можете изменить размер получающегося прямоугольника, чтобы он не был таким сумасшедшим, для печати контракта в Windows 8 необходимо предоставить ему одну страницу. Это не делает пагинацию для вас. В результате вам действительно нужно получить отдельный веб-сайт по одной странице за раз.

Первый подход - основа того, как это сделать. Но вам нужно установить размер прямоугольника в соответствии с размером страницы, переданным вам в задаче печати Windows 8. Это будет основано на выборе принтера пользователем. Например, Письмо против A4 (в Великобритании). Затем, используя свойство Stretch кисти, вы можете убедиться, что оно само обрезается. Затем, используя свойство Transform кисти, вы можете перемещать его вверх и вниз внутри прямоугольника, пока он не покажет страницу, которую вы хотите напечатать.

Вот как:

<Grid Background="Blue">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="995" />
        <ColumnDefinition Width="300" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <WebView Grid.Column="0" x:Name="MyWebView" Source="http://www.stackru.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;
}

Таким образом, пользовательский интерфейс будет выглядеть примерно так: левый столбец - это WebView, второй столбец (средний) - это все-в-одном, как наше первое решение, а третий - это повторитель, показывающий отдельные страницы, готовые к печати.

введите описание изображения здесь

Конечно, магия действительно в методе GetWebPages()! Я не против сказать, что это просто чудо, сделанное довольно легко благодаря тому, как работают C# и Transforms.

Обратите внимание, это не завершено. Да, это разбивает страницу для вас, но я не могу быть уверен, сколько маржи вы хотите на своей странице. Таким образом, требуемая настройка крошечная, но я хотел упомянуть об этом. Это 98% кода, который вам понадобится, чтобы разбить WebView и подготовить его для задачи печати Windows 8 в ответ на событие paginate. Затем передайте прямоугольники ему по одному.

Сказав это, это, вероятно, наиболее полное решение этой проблемы в Интернете.:)

Удачи!!

Вот основной синтаксис печати.

PrintManager.PrintTaskRequested += printManager_PrintTaskRequested;
void printManager_PrintTaskRequested(
    Windows.Graphics.Printing.PrintManager sender,
    Windows.Graphics.Printing.PrintTaskRequestedEventArgs args)
    {
        ...
    }
Другие вопросы по тегам