我知道你可能已經解決了這一點,但這裏要說的是母版頁和MVC(和ASP.Net形式,以及)有效的解決方案。
我首先嚐試覆蓋母版頁的Render方法,然後使用RenderControl渲染ContentPlaceHolders,並用渲染結果替換模板中的某些標記。這適用於ASP.Net表單,但不適用於MVC - 這種方式<% using (Html.BeginForm("A","B")) { %>
總是會導致在doctype之前在頁面的頂部呈現表單標記。
解決方案
檢索模板,並將其分割成其組成部分,有些是文字部分,有些是佔位符部分。在您的母版頁中,您有一個HTML文檔和您的佔位符 - 不僅是您的佔位符。這樣VS設計師就不會抱怨。但是,渲染時,首先清除Controls集合,然後將每個部分添加爲LiteralControl或ContentPlaceHolder。您只需將實際渲染保留到ASP.Net。以下是靈感代碼。
母版頁:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title runat="server"></title>
<asp:PlaceHolder ID="HeadPlaceHolder" runat="server">
<script type="text/javascript" src="/cnnet/Resources/Js/jquery-1.8.1.min.js"></script>
</asp:PlaceHolder>
<asp:ContentPlaceHolder ID="HeadContentPlaceHolder" runat="server"/>
</head>
<body>
<asp:ContentPlaceHolder ID="MainContentPlaceHolder" runat="server" />
</body>
</html>
母版頁的代碼隱藏:
private HtmlHead originalPageHeader;
static readonly Regex HeadStartRegex = new Regex(@"^\s*<head[^>]*>");
static readonly Regex HeadEndRegex = new Regex(@"</head>\s*$");
static readonly Regex TitleRegex = new Regex(@"<title>[^<]*</title>");
public Default() { Init += Default_Init; }
private void Default_Init(object sender, EventArgs e) { DoScraping(); }
protected override void Render(HtmlTextWriter writer)
{
// get content from html head control generated via Page.Header:
string headHtml = RenderControl(originalPageHeader);
Controls.Remove(originalPageHeader);
headHtml = HeadStartRegex.Replace(headHtml, string.Empty);
headHtml = HeadEndRegex.Replace(headHtml, string.Empty);
headHtml = TitleRegex.Replace(headHtml, string.Empty);
// head.Controls.Add(new LiteralControl(headHtml)); doesnt work if head content placeholder contains code blocks (i.e. <% ... %>)
// Instead add content this way:
int headIndex = Controls.IndexOf(HeadContentPlaceHolder);
if (headIndex != -1)
Controls.AddAt(headIndex + 1, new LiteralControl(headHtml));
base.Render(writer);
}
private void DoScraping()
{
IList<PagePart> parts = ... // do your scraping and splitting into parts
Controls.Clear();
foreach (PagePart part in parts)
{
var literalPart = part as LiteralPart;
if (literalPart != null)
{
Controls.Add(new LiteralControl(literalPart.Text));
}
else
{
var placeHolderPart = part as PlaceHolderPart;
switch (placeHolderPart.Type)
{
case PlaceHolderType.Title:
Controls.Add(new LiteralControl(HttpUtility.HtmlEncode(Page.Title)));
break;
case PlaceHolderType.Head:
Controls.Add(HeadPlaceHolder);
Controls.Add(HeadContentPlaceHolder);
break;
case PlaceHolderType.Main:
Controls.Add(new LiteralControl("<div class='boxContent'>"));
Controls.Add(MainContentPlaceHolder);
Controls.Add(new LiteralControl("<div/>"));
break;
}
}
}
}
private string RenderControl(Control control)
{
string innerHtml;
using (var stringWriter = new StringWriter())
{
using (var writer = new HtmlTextWriter(stringWriter))
{
control.RenderControl(writer);
writer.Flush();
innerHtml = stringWriter.ToString();
}
}
return innerHtml;
}
配件:
public class PagePart {}
public class LiteralPart : PagePart
{
public LiteralPart(string text) { Text = text; }
public string Text { get; private set; }
}
public class PlaceHolderPart : PagePart
{
public PlaceHolderPart(PlaceHolderType type) { Type = type; }
public PlaceHolderType Type { get; private set; }
}
public enum PlaceHolderType { Title, Head, Main }
分裂:
class PlaceHolderInfo
{
public PlaceHolderInfo(PlaceHolderType type, Regex splitter)
{
Type = type;
Splitter = splitter;
}
public PlaceHolderType Type { get; private set; }
public Regex Splitter { get; private set; }
}
private static readonly List<PlaceHolderInfo> PlaceHolderInfos = new List<PlaceHolderInfo>
{
new PlaceHolderInfo(PlaceHolderType.Title, new Regex(TitleString)),
new PlaceHolderInfo(PlaceHolderType.Head, new Regex(HeadString)),
new PlaceHolderInfo(PlaceHolderType.Main, new Regex(MainString)),
};
private static List<PagePart> SplitPage(string html)
{
var parts = new List<PagePart>(new PagePart[] { new LiteralPart(html) });
foreach (PlaceHolderInfo info in placeHolderInfos)
{
var newParts = new List<PagePart>();
foreach (PagePart part in parts)
{
if (part is PlaceHolderPart)
{
newParts.Add(part);
}
else
{
var literalPart = (LiteralPart)part;
// Note about Regex.Split: if match is found in beginning or end of string, an empty string is returned in corresponding end of returned array.
string[] split = info.Splitter.Split(literalPart.Text);
for (int i = 0; i < split.Length; i++)
{
newParts.Add(new LiteralPart(split[i]));
if (i + 1 < split.Length) // If result of Split returned more than one string, it means there was a match and we insert the placeholder between each string
newParts.Add(new PlaceHolderPart(info.Type));
}
}
}
parts = newParts;
}
return parts;
}
請注意,此解決方案很容易擴展到更多佔位符(麪包屑,菜單,您的名稱)。它不會假定模板中佔位符的順序或其存在的順序。
編輯1: 我原來從Render
方法調用DoScraping
。事實證明,這是有問題的,因爲它重新編制了Web表單中的控件名稱(例如ctl00 $ MainContentPlaceHolder $ RequestingRepeater $ ctl01 $ ctl01)。它搞砸了數字到OnCommand
在中繼器內的按鈕停止工作的點。控件的重新排序必須儘可能早地發生,以避免這種情況,所以現在已將它移動到Init
。
編輯2: 某些頁面使用Page.Header
生成樣式和腳本標記。爲了支持這個功能,我添加了一些黑客來保留原始<head>
標記並在渲染時插入生成的內容。
您好MrSharky - 不幸的是,這個問題(?)的範圍太廣泛,而且在您尋找的實際幫助方面還不太清楚。你描述了很多,但沒有解釋你在哪裏遇到問題,你曾經嘗試過什麼,以及你需要什麼樣的幫助。 – Oded 2012-08-07 09:37:00
你可以在主頁中使用文字嗎?你可以將頭部HTML細分,然後將其存儲在一個字符串中,然後在主頁面代碼中設置literal = header頭部 – dtsg 2012-08-07 09:37:28
@Oded道歉,目前這並不是什麼問題,你是對的。我會編輯它以更具體一點。謝謝 – MrSharky 2012-08-07 10:05:05