【发布时间】:2026-01-28 04:35:01
【问题描述】:
更新 3
这个问题现在有赏金了。示例项目和问题简介位于页面底部的 TL;DR; 下,因此请节省一些阅读时间并跳到最后!
...
我一直试图通过 NavigateToString 使用静态加载的页面从 JerryNixon 那里获得这个非常详细的、赞成的答案。我不明白为什么这不起作用,但诚然,代码的某些部分绝对让我感到困惑。
最初的答案是here,但为了完整起见,我将在此处复制代码。 Jerry 为想要从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.*.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 中删除 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 缩小到一个非常窄的视图
(请参阅更新说明,了解为何删除此内容)
然后屏幕变灰。 (发一张灰屏的截图感觉有点傻,但我在这里尽量做到彻底)
应用程序不会崩溃。没有调试消息出现,没有异常发生。 好像Grid 被简单地删除了。 罢工>。这不是启动画面(我设置为蓝色),也不是应用程序背景(深灰色)。就好像在页面顶部加载了其他内容。
我已尝试调整代码的每一部分,但我似乎无法找出导致问题的原因。此外,这段代码的某些部分让我很困惑。例如,在Load_Completed 方法中
MyWebViewRectangle.Fill = GetWebViewBrush(MyWebView);
MyPrintPages.ItemsSource = GetWebPages(MyWebView, new Windows.Foundation.Size(100d, 150d));
MyWebView.Visibility = Windows.UI.Xaml.Visibility.Visible;
Line1: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;
据我所知,webview 从来不是Collapsed,但它被设置为Visible 三倍。
如果有人可以向我解释这些(甚至可能是 JerryNixon 本人?),我会真的感激不尽。我花了几个月的时间开发一个应用程序,这是最后一块拼图。没有打印能力,我无法启动!
更新
今天早上有了一些发现。我一直在 XAML 中设置WebView 的宽度。没有这个,即使是最小的文件也会失败。基于这个发现,我将 html 文件本身的宽度设置为 800 像素,并且它起作用了。万岁,问题解决了,对吧?很不幸的是,不行。我再次尝试使用更长的文件(红发联盟的完整版本,here),同样的问题再次发生。现在它变得更奇怪了。
我在 GetWebPages 方法中的 webView.Height = _ContentHeight; 处插入了一个断点。这表明 _ContentHeight 正好是“13241”。
但是,插入断点会使代码工作。一旦我休息并继续,一切似乎都在加载。尽管再次奇怪的是,在我将鼠标悬停在滚动条上之前,WebView 是不可见的。
如果我删除断点,我会再次出现灰屏。
如果我手动将 _ContentHeight 设置为 13230,则页面会加载。这似乎是一个神奇的数字。任何高于此值的页面都会失败。但是,如果我将 html 的宽度更改为小于 800px,它也会失败。所以从逻辑上讲,存在某种 800:13230 像素(或 1:16.5375)的神奇比例。如果我超过这个比例,我就会启动灰色的死亡屏幕。我可以禁用红色矩形并将GetWebPages 限制为 3 页,并且灰屏仍然存在。这告诉我问题出在WebView 本身
如果我设置断点,问题就会消失。
当它起作用时,还要注意MyWebViewRectangle 中的额外空白和MyPrintPages 中的额外空白页:
注意:我还添加了 NateDiamond 对事件 LongRunningScriptDetected、UnsafeContentWarningDisplaying 和 UnviewableContentIdentified 的建议
这是我的示例项目的完整源代码: https://onedrive.live.com/redir?resid=EE99EF9560A6740E!110509&authkey=!ACrZgm6uq5k5yck&ithint=file%2czip
更新 2
一些成功。
我将一些标题放入我的示例文件中(通过反复试验找到每个计算页面的“底部”)并增加页面大小以便我可以看到标记。虽然有 9 个页面,但只渲染了 5 个和 6 个的一小部分。 9 个页面对象是由GetWebPages 创建的,但只有 5ish 呈现了 HTML 内容。其余为空
(注意,我更改了背景颜色,因为蓝色上的红色让我偏头痛)
我已经浏览了代码并进行了一些修改,现在我完全不再出现灰屏了。但是,我运行它的每 3 次中大约有 2 次,只有第一页被渲染,并且被裁剪。这似乎是完全随机的。如上所述,当呈现 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;
加载并观察。文档共有 9 页。
- GetWebPages 有时只加载一页,被裁剪
- 其余时间,GetWebPages 加载页面 1-5、6 和 3 空白页面的一部分
这就是回答这个问题所需要知道的几乎所有内容。
我已经在这个问题上悬赏。我正在寻找这个问题的解决方案,如果可能的话,我正在寻找一种方法来为每个页面添加填充,以便文本不会跑到边缘。
【问题讨论】:
-
在 Windows 8.1 中有很多成功和失败状态的事件,例如 LongRunningScriptDetected、UnsafeContentWarningDisplaying 和 UnviewableContentIdentified。尝试添加这些事件并查看是否有任何火灾。另一个要尝试的是新的
NavigateToLocalStreamUri方法。 -
谢谢内特。我刚刚添加了所有这些事件,并为每个事件添加了
throw new Exception...。没有例外。同样,只是一个灰屏。我确认这也不是网格被删除 - 我页面本身的背景颜色是深灰色。这种灰色是“应用启动”灰色。 -
你试过不同尺寸的屏幕吗?尝试在具有不同大小屏幕的模拟器中加载它,看看是否会改变数字。
标签: c# printing webview windows-store-apps brush