2014-09-29 70 views
4

UPDATE 3

现在有一个关于此问题的赏金。示例项目和问题摘要位于TL,DR;为自己节省一些阅读并跳到最后!从Windows应用商店应用中的WebView打印静态内容

...

我一直在试图摆脱JerryNixon通过NavigateToString使用静态页面加载这个工作非常详细,upvoted答案。我不明白为什么这不应该起作用,但不可否认的是,部分代码让我感到困惑。

原来的答案是here但我会在这里复制代码为完整起见。杰里提供了以下样品/解决方案,谁想要从WebView

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

我唯一的变化是打印删除从web视图的Source属性,这行添加到MainPage()方法

var html = await Windows.Storage.PathIO.ReadTextAsync("ms-appx:///Assets/sherlock.html"); 
MyWebView.NavigateToString(html); 

Sherlock.html是Arthur Conan Doyle故事的摘录,红头联盟,此HTML页面的完整代码是here - 请注意,接近结尾的部分重复多次。这是在测试中完成的,我将在下面解释

本示例最初为我工作,在一个小文件上。 (Sherlock.html没有填充章节)

但是,当我获得超过某个文件大小(通常大约4000字+)时,样本发生以下行为。

的WebView中收缩到一个非常狭隘的观点

(明白为什么这个被剔除更新笔记)

,然后屏幕变成灰色。 (我觉得有点傻发布一个灰色的屏幕截图,但我想彻底这里)

enter image description here

应用程序不崩溃。没有调试消息出现,不会发生异常。 就好像 Grid被简单地移除一样。 。这不是闪屏(我已经设置蓝色),它不是应用程序背景(深灰色)。就好像在页面的顶部加载了其他内容。

我试过调整代码的每一部分,但我似乎无法隔离是什么原因造成的问题。此外,这些代码的一部分只是混淆了我的地狱。例如,在Load_Completed方法

MyWebViewRectangle.Fill = GetWebViewBrush(MyWebView); 
MyPrintPages.ItemsSource = GetWebPages(MyWebView, new Windows.Foundation.Size(100d, 150d)); 
MyWebView.Visibility = Windows.UI.Xaml.Visibility.Visible; 

线路1:MyWebViewRectangle充满WebView的一个镜头。为什么?这个控制从不再被引用。我想这可能是用户得到的页面更清晰的视野,但它似乎起不到任何编程目的

3号线:MyWebView.Visibility设置为Visible再次出现这种情况后,在GetWebViewBrush

var _OriginalVisibilty = webView.Visibility; 
webView.Visibility = Windows.UI.Xaml.Visibility.Visible; 
// and a few lines later... 
webView.Visibility = _OriginalVisibilty; 

据我所知道的,网页流量是从不Collapsed,但它设置为Visible三次。

如果任何人都可以向我解释任何这个(也许甚至是杰里尼克森自己?)我会真的欣赏它。我花了好几个月的时间研究一个应用程序,这是最后一块难题。如果没有打印能力,我无法启动!

UPDATE

今天早上做了一些发现。我一直在XAML中设置WebView的宽度。没有这个,即使最小的文件都失败了。根据这个发现,我将HTML文件本身的宽度设置为800px,并且它工作正常。万岁,问题解决了吧?很不幸的是,不行。我再次尝试用更长的文件(完整版本红头发的联盟,here)并且同样的问题再次发生。它现在得到了很多怪物

我在GetWebPages方法中插入了一个断点webView.Height = _ContentHeight;。这表明我_ContentHeight完全是“13241”。

但是,插入断点的使代码工作。一旦我打破并继续,这一切似乎加载。虽然奇怪,WebView是隐藏的,直到我将鼠标悬停在滚动条上。

如果我删除断点,我再次看到灰色屏幕。

如果我手动将_ContentHeight设置为13230,则会加载页面。这似乎是神奇的数字。任何高于此的内容都会失败。但是,如果我将html的宽度更改为小于800像素,它也会失败。因此逻辑上,800:13230像素(或1:16.5375)具有某种魔术比例。如果我超过这个比例,我就开始了死亡的灰色屏幕。我可以禁用红色矩形并将GetWebPages限制为3页,灰色屏幕仍然存在。这告诉我,问题是WebView本身

如果我设置了断点,这个问题就会消失。

还要注意在MyWebViewRectangle和额外的空白页的多余的空格中MyPrintPages时,它的工作:

Working result, but with extra whitespace and blank pages appended

注:我还添加事件LongRunningScriptDetectedUnsafeContentWarningDisplaying的NateDiamond的建议,并UnviewableContentIdentified

以下是我的示例项目的完整源代码: https://onedrive.live.com/redir?resid=EE99EF9560A6740E!110509&authkey=!ACrZgm6uq5k5yck&ithint=file%2czip

更新2

一些成功。

我把一些头文件放到我的示例文件中(通过试验和错误找到每个计算页面的“底部”),并调整页面大小以便可以看到标记。尽管有9页,但只有5页和6页的一小部分被渲染。 9页面对象由GetWebPages创建,但只有5ish已呈现HTML内容。其余的都是空

nothing past page 5

(注意,我改变了背景颜色为蓝色,红色是给我一个偏头痛)

我已经通过代码消失了,做了一些修改,现在我不再得到灰色屏幕。然而,每3次运行一次,只有第一页被渲染,并被裁剪。这似乎完全是随机的。如所述,当9页提供时并不是全部都有内容。

这里是我的变化:

增加了新的方法Resize_WebView()

public void ResizeWebView() 
{ 
    OriginalHeight = MyWebView.Height; 

    var _WidthString = MyWebView.InvokeScript("eval", new[] { "document.body.scrollWidth.toString()" }); 
    int _ContentWidth; 
    if (!int.TryParse(_WidthString, out _ContentWidth)) 
     throw new Exception(string.Format("failure/width:{0}", _WidthString)); 
    MyWebView.Width = _ContentWidth; 

    // ask the content its height 
    var _HeightString = MyWebView.InvokeScript("eval", new[] { "document.body.scrollHeight.toString()" }); 
    int _ContentHeight; 
    if (!int.TryParse(_HeightString, out _ContentHeight)) 
     throw new Exception(string.Format("failure/height:{0}", _HeightString)); 
    MyWebView.Height = _ContentHeight; 
} 

MyWebView_LoadCompleted注释掉矩形填充,添加调用ResizeWebView():

void MyWebView_LoadCompleted(object sender, NavigationEventArgs e) 
{ 
    ResizeWebView(); 

    //MyWebViewRectangle.Fill = GetWebViewBrush(MyWebView); 
    MyPrintPages.ItemsSource = GetWebPages(MyWebView, new Windows.Foundation.Size(300d, 450d)); 
} 

GetMyWebPages改变地方刷子被加载:

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; 

    // Manually set _ContentHeight: comment out the above block and uncomment this to test. 
    // int _ContentHeight = 13230; 
    // webView.Height = _ContentHeight;*/ 

    // how many pages will there be? 
    //var _Scale = page.Width/_ContentWidth; 
    var _Scale = page.Width/webView.Width; // now sourced directly from webview 
    //var _ScaledHeight = (_ContentHeight * _Scale); 
    var _ScaledHeight = (webView.Height * _Scale); // now sourced directly from webview 
    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 }, 
     }; 
     var _Brush = GetWebViewBrush(webView); 
     _Brush.Stretch = Stretch.UniformToFill; 
     _Brush.AlignmentY = AlignmentY.Top; 
     _Brush.Transform = _Page.Tag as TranslateTransform; 
     _Page.Fill = _Brush; 
     /*_Page.Loaded += async (s, e) => 
     { 
      var _Rectangle = s as Windows.UI.Xaml.Shapes.Rectangle; 
      var _Brush = await GetMyWebViewBrush(webView); 
      _Brush.Stretch = Stretch.UniformToFill; 
      _Brush.AlignmentY = AlignmentY.Top; 
      _Brush.Transform = _Rectangle.Tag as TranslateTransform; 
      _Rectangle.Fill = _Brush; 
     };*/ 
     _Pages.Add(_Page); 
    } 
    return _Pages; 
} 

GetWebView

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

这正在成为一个严重的问题史诗现在去掉不必要的调整大小代码。

TL; DR;

这是更新的项目。 https://onedrive.live.com/redir?resid=EE99EF9560A6740E!110545&authkey=!AMcnB_0xKRhYHIc&ithint=file%2czip

加载并观察。文档中有9个页面。

  • GetWebPages偶尔只加载一个页面,裁剪
  • 的其余时间,GetWebPages负荷1-5页,第6个3

空白页部分这是几乎所有你需要知道回答这个问题。

我已经在这个问题上给了一个赏金。我正在寻找这个问题的解决方法,并且如果可能的话,为每个页面添加填充以便文本不会运行到边缘。

+0

在Windows 8.1有一堆成功和失败状态,如LongRunningScriptDetected,UnsafeContentWarningDisplaying和UnviewableContentIdentified事件。尝试添加这些事件并查看是否有火灾。另一种尝试是新的['NavigateToLocalStreamUri'](http://msdn.microsoft.com/en-US/library/windows/apps/windows.ui.xaml.controls.webview.navigatetolocalstreamuri.aspx)方法。 – 2014-09-29 22:22:08

+0

谢谢Nate。我只是添加了所有这些事件,并为每个事件添加了一个“抛出新的异常......”。没有例外。再次,只是一个灰色的屏幕。我证实这不是网格也被删除 - 我的页面背景颜色是灰暗的。这灰色是“应用程序启动”灰色。 – roryok 2014-09-30 07:17:33

+0

你在不同尺寸的屏幕上试过了吗?尝试在不同大小的屏幕模拟器中加载它,看看是否改变了数字。 – 2014-09-30 18:48:24

回答

0

[更新]

事实上,它被切断在相同的位置与这个新的代码是非常奇怪的。这将表明数据不存在于WebViewBrush中。如果将整个画笔渲染到一个控件,它会渲染一切吗?如果我的理论是正确的,你应该只看到第6页的截止点。这开始闻起来就像Surface Pro上的视频驱动程序错误。 Surface pro使用英特尔视频芯片组并使用共享即系统内存。你应该有足够的渲染画笔的单个实例(全部9页)。请记住,即使在更好的硬件上,这种方法仍然可能会导致大量页面上的资源问题。

如果您有机会,请尝试将其装载到另一台带有不同制造商的视频卡的计算机上,以确认它确实可行吗?我将尝试挖掘Surface Pro 1并查看是否可以重现您的发现。

我需要警告有关XAML打印的已知资源缺陷,然后才能沿着这条路前进。 XAML打印子系统要求您在渲染之前将所有页面传递给它。然后它将整个文档发送到打印机。这要求每个页面都被缓存为XAML,然后每个页面都被渲染为位图。这一切都发生在主内存中。您可能会丢失20页左右的内​​容,但一旦过去了,您将很快耗尽系统资源。由于内存压力,五百到一百页可能会导致运行时关闭你。在资源较低的设备上,您将获得更少的页面。

最初我以为你的目标是打印HTML页面。下面的解决方案是完美的。但是,如果您的最终目标是允许用户从应用程序打印大型文档,那么真正的答案(以及Windows Store应用程序的唯一解决方案)就是使用Direct2D和DirectWrite。这些技术可让您将页面“流”到打印机缓存中。打印机缓存由磁盘支持,不会导致相同的内存压力问题(尽管您理论上仍然可能会用完磁盘空间)。毋庸置疑,这是理想的解决方案,但需要大量的专业知识。您需要了解C++/CX以及Direct2D的相关信息,才能正确分页。

Direct2Dapp printing sample

我希望这有助于

詹姆斯


我把这个今天仔细看,我认为你正在运行到是资源限制。我无法在我的工作站类机器上重现问题,而我的同事无法在他的工作站类笔记本电脑上重现问题。我在代码中看到的是,您正在为每个页面创建一个新的画笔。即使您正在转换画笔,整个WebView也会转换为位图,每个页面都是一个非常大的位图。这会对XAML丰富的排字程序造成资源限制。由于合成器基于D3D,因此视频卡上的纹理内存可能会用完。

我想我有一个解决方案给你。我不会说谎,它很丑,但它为我工作,我希望它能为你工作。基本上我通过画笔将页面部分渲染到XAML中声明的隐藏矩形。然后我使用RenderTargetBitmap来渲染隐藏的矩形。这只会渲染我们需要的WebView部分。然后我将RenderTargetBitmap设置为Image的源代码。我将这些图像添加到页面集合中。 pages集合被设置为你的ItemsControl,而bob是你的叔叔。

大部分的变化是GetWebPages:

async Task<bool> GetWebPages(WebView webView, Windows.Foundation.Size page) 
{ 
    // how many pages will there be? 
    var _Scale = page.Width/webView.Width; // now sourced directly from webview 
    var _ScaledHeight = (webView.Height * _Scale); // now sourced directly from webview 
    var _PageCount = (double)_ScaledHeight/page.Height; 
    _PageCount = _PageCount + ((_PageCount > (int)_PageCount) ? 1 : 0); 

    var _Brush = GetWebViewBrush(webView); 

    for (int i = 0; i < (int)_PageCount; i++) 
    { 
     var _TranslateY = -page.Height * i; 
     // You can probably optimize this bit 
     _RenderSource.Height = page.Height; 
     _RenderSource.Width = page.Width; 
     Margin = new Thickness(5); 

     _Brush.Stretch = Stretch.UniformToFill; 
     _Brush.AlignmentY = AlignmentY.Top; 
     _Brush.Transform = new TranslateTransform { Y = _TranslateY }; 
     _RenderSource.Fill = _Brush; 

     RenderTargetBitmap rtb = new RenderTargetBitmap(); 

     await rtb.RenderAsync(_RenderSource); 

     var _iPge = new Image 
     { 
      Source = rtb, 
      Margin = new Thickness(10) 
     }; 

     _Pages.Add(_iPge); 
    } 
    return true; 
} 

整个修改的项目可以在这里找到:http://1drv.ms/1y91iv7

请给它一个尝试,让我知道它是否适合你。

PS有一些布局问题和网页问题,我没有尝试解决。

我希望这有助于

詹姆斯

+0

我真的很感激所花费的时间,我很乐意说这可以解决这个问题,但它仍然在我的同一个地方切断。你可能是对的资源 - 我的开发机器是一个4GB的表面亲。我想我必须尝试一种完全不同的方法 - 将HTML转换为XAML,将其渲染为RichTextBlock并从那里打印。这不是我想要的,但它应该有希望解决内存问题。 – roryok 2014-10-09 08:31:34

相关问题