在调用ASP.NET菜单服务器控件的RenderControl方法时,我收到NullReferenceException异常。
我使用以下代码动态创建了控件:
private string RenderMenuHTML()
{
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter hw = new HtmlTextWriter(sw);
string menuXML = MenuManager.GetMenuXML();
if (!string.IsNullOrEmpty(menuXML))
{
Menu menuControl = new UI.Menu();
menuControl.ID = "menu";
// Required properties to use RenderControl
menuControl.SkipLinkText = string.Empty;
menuControl.StaticPopOutImageUrl = "fake.gif";
menuControl.ScrollUpImageUrl = "fake.gif";
menuControl.ScrollDownImageUrl = "fake.gif";
// Data binding
XmlDataSource xmlDS = new XmlDataSource();
xmlDS.ID = "xdsMenu";
xmlDS.Data = menuXML;
xmlDS.XPath = "MenuItems/MenuItem";
// Menu data binding
MenuItemBinding menuItemBinding = new MenuItemBinding();
menuItemBinding.DataMember = "MenuItem";
menuItemBinding.ValueField = "Value";
menuItemBinding.TextField = "Text";
menuItemBinding.ToolTipField = "Text";
menuItemBinding.NavigateUrlField = "NavigateUrl";
menuControl.DataBindings.Add(menuItemBinding);
menuControl.DataSource = xmlDS;
menuControl.DataBind();
menuControl.RenderControl(hw); // <-- Problem here
}
return sb.ToString();
}
我需要做的是获取控件生成的HTML代码,这样我就不必手动生成它。我绑定了一个从递归菜单层次结构构建的XML数据源。
我已经查看了异常的详细信息,而调试器似乎没有说明任何内容。
当我将控件放在PlaceHolder中时,一切正常,但我需要的是HTML代码。
我似乎缺少Menu或MenuItem对象中的一些必需属性,但我在网上找不到任何依赖于此的内容。
有什么想法吗?
由于
答案 0 :(得分:1)
我假设控件使用其上下文(例如它所在页面之类的东西)来做某事。虽然它不在页面上,但它无法访问此信息,这就是为什么它在占位符中工作而不在其外部。在调用rendercontrol方法之前,我建议将其添加到页面中的占位符。如果你想在之后从页面中删除它,那么没有什么可以阻止你这样做。我不确定是否可能存在副作用(例如,您可能需要注意ID的某些命名等,因为它们可能取决于您将其放在页面中的位置)。
我还会继续质疑你用这个HTML做什么?如果您在页面上使用它,为什么不只是将控件放在页面中并让它做它的事情?如果您在其他地方使用它,那么为什么不使用静态HTML?不是说你正在做的事情是错的,我只是在努力思考你在做什么,所以想要确保你一定想到你为什么这样做。 :)
答案 1 :(得分:1)
您可以使用init Event
初始化您的Control这是初始化ASP页面上的Menu控件的示例
protected void Menu1_Init(object sender, EventArgs e)
{
List<Category> categories = db.GetCategory();
for (int i = 0; i < categories.Count; i++)
{
((Menu)sender).Items.Add(new MenuItem(categories.ElementAt(i).Name));
}
}
答案 2 :(得分:0)
我相信您需要覆盖Render或RenderChildren事件。
以下是Microsoft的一个示例
// Override default implementation to Render children according to needs.
protected override void RenderChildren(HtmlTextWriter output)
{
if (HasControls())
{
// Render Children in reverse order.
for(int i = Controls.Count - 1; i >= 0; --i)
{
Controls[i].RenderControl(output);
}
}
}
protected override void Render(HtmlTextWriter output)
{
output.Write("<br>Message from Control : " + Message);
output.Write("Showing Custom controls created in reverse" +
"order");
// Render Controls.
RenderChildren(output);
}
这适用于标准ASPX页面:
protected override void Render(HtmlTextWriter writer)
{
StringBuilder sb = new StringBuilder();
HtmlTextWriter htw = new HtmlTextWriter(new StringWriter(sb));
base.Render(htw);
writer.Write(sb.ToString());
Logger.Write("TransferToColdFusion HTML: " + sb.ToString(), "Debug");
}
尝试此方法并传入菜单控件。
public string RenderControl(Control ctrl)
{
StringBuilder sb = new StringBuilder();
StringWriter tw = new StringWriter(sb);
HtmlTextWriter hw = new HtmlTextWriter(tw);
ctrl.RenderControl(hw);
return sb.ToString();
}
答案 3 :(得分:0)
看起来控件依赖于页面生命周期来初始化RenderControl中使用的某个变量。
您必须Debug the .NET Framework Source Code才能看到它是什么。
答案 4 :(得分:0)
我测试了你的代码并且它工作得很好...... hw在RenderControl方法之后有这个。
> <div id="menu"> <ul class="level1">
> <li><a title="test" class="level1"
> href="www.google.com">test</a></li>
>
</ul> </div>
The only difference was that I used a sample xml = @"<MenuItems><MenuItem Value='Test' Text='test' NavigateUrl='www.google.com'>Test</MenuItem></MenuItems>";
因此可能与您的Menu Xml源有关。