2011-01-05 37 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)); 

     } 
    } 
相關問題