2013-06-11 1 views
16

У меня есть Metro App и я пытаюсь распечатать содержимое элемента управления WebView. Используя пример печати MSDN в качестве исходной ссылки. Я просто изменить XAML в printableArea следующим образом:Как распечатать содержимое WebView в приложении Windows Store?

<RichTextBlock> 
     <Paragraph> 
      <InlineUIContainer> 
       <WebView Width="800" Height="2000" Source="http://www.stackoverflow.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#refinementChanges=180&pageNumber=1&showMore=false

Хочу дать всем, кто может решить эту проблему 100 пунктов награду в , Поблагодарите прохождение, образец кода или макет проекта в качестве решения.

+0

Какова высота RichTextBlock? Установлен ли клип? Интересно, печатает ли высота RTB/Paragraph вместо WebView. –

ответ

28

Конечно, здесь вы идете.

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

Как это:

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

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

enter image description here

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

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

Первый подход - основа того, как это сделать. Но вам нужно исправить размер прямоугольника до размера страницы, переданного вам при задании печати Windows 8. Это будет основано на выборе принтера для пользователя. Например, Letter to 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.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; 
} 

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

enter image description here

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

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

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

Удачи!

+1

Спасибо, мистер Никсон !!! Ваши предложения были на месте. Я обновил ваш ответ, чтобы включить код для полей. Бесконечно благодарен. Вы спасатель жизни. Мое приложение теперь готово для магазина приложений :) – c0D3l0g1c

+1

Очень гладкий - лучше всего в сети :) –

+0

У меня с трудом получается, чтобы это сработало - я загружаю свой контент статически, используя 'NavigateToString'. Код работает для файла объемом около 4000 слов, но если я его немного починю, он перестанет работать. WebView сжимается, элемент ItemsControl пуст, и примерно через 4 секунды экран становится серым. Нет исключений или ошибок. Есть идеи? – roryok

0

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

PrintManager.PrintTaskRequested += printManager_PrintTaskRequested; 
void printManager_PrintTaskRequested(
    Windows.Graphics.Printing.PrintManager sender, 
    Windows.Graphics.Printing.PrintTaskRequestedEventArgs args) 
    { 
     ... 
    } 
Смежные вопросы