2011-01-05 81 views
1

当调用ASP.NET菜单服务器控件的RenderControl方法时,我遇到了NullReferenceException异常。在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对象中的一些必需的属性,但我无法在Web上找到任何依赖此的属性。

任何想法?

谢谢

回答

1

我假设控件使用它的上下文(即像它所在的页面那样的东西)来做某事。虽然它不在页面上,但它不能访问这个信息,这就是为什么它在占位符中工作而不在它之外。我建议在调用rendercontrol方法之前将其添加到页面中的占位符。如果您想在之后将其从页面中删除,则无法阻止您这样做。我不确定是否可能有副作用(例如,您可能需要小心一些ID的命名等,因为它们可能取决于您将它放在页面中的位置)。

我还会继续质疑你用这个HTML做什么?如果你在页面上使用它,为什么不把控件放在页面中并让它做到这一点?如果你在其他地方使用它,那么为什么不使用静态HTML?不是说你在做什么是错的,我只是在努力思考你在做什么,所以想要确保你明确地考虑过你为什么要这样做。 :)

+0

我有一个包含来自预定义模板的HTML代码的字符串。我想用实际菜单替换{Template.Menu}之类的东西,所以我想我只是使用RenderControl来获取代码。 – Jason 2011-01-05 16:09:55

+1

@Jason:啊,好的。这就说得通了。可能有更好的方法来做这件事,但也可能是因为你正在做的事而被过度劳累。 ;-)我认为我的建议应该让你有所需要。 – Chris 2011-01-05 16:12:09

+0

你可能是对的,我想我会使用HtmlTextWriter代替Menu控件来手工生成代码。谢谢你的建议! – Jason 2011-01-05 16:17:52

0

我相信你需要重写Render或RenderChildren事件。

下面是来自微软

// 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"); 
} 

试试这个方法,并将您的菜单控制。

​​
+0

没有错误的初始化菜单控制的例子,但sb.ToString()没有返回初始化控制。 – Jason 2011-01-05 15:34:30

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源代码有关。

1

您可以通过使用init事件

这是重写这些方法后,ASP页

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

     } 
    }