TL; DR: Попробуйте использовать Html.Partial
вместо Renderpage
Я получал Object reference not set to an instance of an object
, когда пытался сделать вид в представлении, отправив ему модель, например это:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
Отладка показала, что модель была Null внутри MyOtherView. Пока я не сменил его на:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
И это сработало.
Кроме того, причина, по которой я не имел Html.Partial
для начала, заключалась в том, что Visual Studio иногда выдает ошибки, (f9), если он находится внутри другого построенного цикла foreach
, хотя это не ошибка:
@inherits System.Web.Mvc.WebViewPage
@{
ViewBag.Title = "Entity Index";
List<MyEntity> MyEntities = new List<MyEntity>();
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
}
<div>
@{
foreach(var M in MyEntities)
{
// Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
@Html.Partial("MyOtherView.cshtml");
}
}
</div>
Но я смог запустить приложение без проблем с этим " ошибка". Я смог избавиться от ошибки, изменив структуру цикла foreach
, чтобы выглядеть так:
@foreach(var M in MyEntities){
...
}
Хотя я чувствую, что это потому, что Visual Studio неправильно интерпретировала амперсанды и скобки .
Чтобы показать номер страницы и общие страницы, вы можете использовать этот фрагмент javascript в нижнем колонтитуле или коде заголовка:
var pdfInfo = {};
var x = document.location.search.substring(1).split('&');
for (var i in x) { var z = x[i].split('=',2); pdfInfo[z[0]] = unescape(z[1]); }
function getPdfInfo() {
var page = pdfInfo.page || 1;
var pageCount = pdfInfo.topage || 1;
document.getElementById('pdfkit_page_current').textContent = page;
document.getElementById('pdfkit_page_count').textContent = pageCount;
}
И вызвать getPdfInfo со страницей onload
Конечно, pdfkit_page_current и pdfkit_page_count будут двумя элементами, отображающими числа.
Фрагмент, взятый из здесь
На самом деле это намного проще, чем с фрагментом кода. Вы можете добавить следующий аргумент в командной строке: --footer-center [page]/[topage]
.
Как упоминалось в Richard, дополнительные переменные находятся в разделе Footers and Headers документации .
Безопасный подход, даже если вы используете XHTML (например, с тимелеафом). Единственное отличие от решения другого - использование // тэгов.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<script>
/*<![CDATA[*/
function subst() {
var vars = {};
var query_strings_from_url = document.location.search.substring(1).split('&');
for (var query_string in query_strings_from_url) {
if (query_strings_from_url.hasOwnProperty(query_string)) {
var temp_var = query_strings_from_url[query_string].split('=', 2);
vars[temp_var[0]] = decodeURI(temp_var[1]);
}
}
var css_selector_classes = ['page', 'topage'];
for (var css_class in css_selector_classes) {
if (css_selector_classes.hasOwnProperty(css_class)) {
var element = document.getElementsByClassName(css_selector_classes[css_class]);
for (var j = 0; j < element.length; ++j) {
element[j].textContent = vars[css_selector_classes[css_class]];
}
}
}
}
/*]]>*/
</script>
</head>
<body onload="subst()">
<div class="page-counter">Page <span class="page"></span> of <span class="topage"></span></div>
</body>
Последнее примечание: при использовании тимелеафа замените <script>
на <script th:inline="javascript">
.
То, как это должно быть сделано (то есть, если wkhtmltopdf поддерживает его), будет использоваться правильный CSS Paged Media: http://www.w3.org/TR/css3-gcpm/
Я изучаю, что это займет сейчас.
В документации wkhtmltopdf ( http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf-0.9.9-doc.html ) под заголовком «Нижние колонтитулы и заголовки» есть фрагмент кода для достижения нумерации страниц:
<html><head><script>
function subst() {
var vars={};
var x=document.location.search.substring(1).split('&');
for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
for(var i in x) {
var y = document.getElementsByClassName(x[i]);
for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
}
}
</script></head><body style="border:0; margin: 0;" onload="subst()">
<table style="border-bottom: 1px solid black; width: 100%">
<tr>
<td class="section"></td>
<td style="text-align:right">
Page <span class="page"></span> of <span class="topage"></span>
</td>
</tr>
</table>
</body></html>
Существуют также более доступные переменные, которые можно заменить, кроме номеров страниц, для использования в верхних колонтитулах.
Среди нескольких других параметров номер страницы и общий номер страницы передаются в HTML-код нижнего колонтитула как параметры запроса, как указано в официальных документах:
... [номер страницы ] аргументы отправляются в html-документы заголовка / нижнего колонтитула в модуле GET.
blockquote>Источник: http://wkhtmltopdf.org/usage/wkhtmltopdf.txt
Таким образом, решение состоит в том, чтобы получить эти параметры, используя бит JS и превращая их в шаблон HTML. Вот полный рабочий пример HTML нижнего колонтитула:
<!doctype html> <html> <head> <meta charset="utf-8"> <script> function substitutePdfVariables() { function getParameterByName(name) { var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); } function substitute(name) { var value = getParameterByName(name); var elements = document.getElementsByClassName(name); for (var i = 0; elements && i < elements.length; i++) { elements[i].textContent = value; } } ['frompage', 'topage', 'page', 'webpage', 'section', 'subsection', 'subsubsection'] .forEach(function(param) { substitute(param); }); } </script> </head> <body onload="substitutePdfVariables()"> <p>Page <span class="page"></span> of <span class="topage"></span></p> </body> </html>
substitutePdfVariables()
вызывается в телеonload
. Затем мы получаем каждую поддерживаемую переменную из строки запроса и заменяем содержимое во всех элементах соответствующим именем класса.