2010-08-12 79 views
4

我知道这是一种迷恋,但有没有办法控制TagBuilder类在您拨打ToString()时呈现HTML标记的属性的顺序?你可以控制TagBuilder类呈现属性的顺序吗?

即,使得

var tb = new TagBuilder("meta");    
tb.Attributes.Add("http-equiv", "Content-Type");    
tb.Attributes.Add("content", "text/html; charset=utf-8");  
tb.ToString(TagRenderMode.SelfClosing) 

将返回

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 

<meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> 

更改您添加的属性不会改变它的顺序,这似乎是渲染按字母顺序排列

回答

2

尝试使用此类,它继承TagBuilder并重写ToString方法,从Attributes构建SortedDictionary并使用该字典进行呈现。

public class MyTagBuilder : TagBuilder 
    { 
     //required to inherit from TagBuilder 
     public MyTagBuilder(string tagName) : base(tagName){} 

     //new hides the original ToString(TagRenderMode renderMode) 
     //The only changes in this method is that all calls to GetAttributesString 
     //have been changed to GetMyAttributesString 
     public new string ToString(TagRenderMode renderMode) 
     { 
      switch (renderMode) 
      { 
       case TagRenderMode.StartTag: 
        return string.Format(CultureInfo.InvariantCulture, "<{0}{1}>", new object[] { this.TagName, this.GetMyAttributesString() }); 

       case TagRenderMode.EndTag: 
        return string.Format(CultureInfo.InvariantCulture, "</{0}>", new object[] { this.TagName }); 

       case TagRenderMode.SelfClosing: 
        return string.Format(CultureInfo.InvariantCulture, "<{0}{1} />", new object[] { this.TagName, this.GetMyAttributesString() }); 
      } 
      return string.Format(CultureInfo.InvariantCulture, "<{0}{1}>{2}</{0}>", new object[] { this.TagName, this.GetMyAttributesString(), this.InnerHtml }); 
     } 

     //Implement GetMyAttributesString where the Attributes are changed to a SortedDictionary 
     private string GetMyAttributesString() 
     { 
      var builder = new StringBuilder(); 
      var myDictionary = new SortedDictionary<string, string>();  //new 
      foreach (KeyValuePair<string, string> pair in this.Attributes) //new 
      {                //new 
       myDictionary.Add(pair.Key, pair.Value);     //new 
      }                //new 
      //foreach (KeyValuePair<string, string> pair in this.Attributes) 
      foreach (KeyValuePair<string, string> pair in myDictionary) //changed 
      { 
       string key = pair.Key; 
       if (!string.Equals(key, "id", StringComparison.Ordinal) || !string.IsNullOrEmpty(pair.Value)) 
       { 
        string str2 = HttpUtility.HtmlAttributeEncode(pair.Value); 
        builder.AppendFormat(CultureInfo.InvariantCulture, " {0}=\"{1}\"", new object[] { key, str2 }); 
       } 
      } 
      return builder.ToString(); 
     } 
    } 
1

我拆开TagBuilder.ToString()与反射,这是代码的键位:

foreach (KeyValuePair<string, string> pair in this.Attributes) 
{ 
    string key = pair.Key; 
    string str2 = HttpUtility.HtmlAttributeEncode(pair.Value); 
    builder.AppendFormat(CultureInfo.InvariantCulture, " {0}=\"{1}\"", new object[] { key, str2 }); 
} 

所以,我要说不 - this.AttributesIDictionary<string,string>接口,列举了当“在返回的项目的顺序未定义“,根据MSDN。

+2

仅供参考,以修改排序行为,如果你看一下标记生成器构造函数,IDictionary实际上是一个SortedDictionary – 2012-06-19 21:40:35

0

我不想重写所有的代码,所以我改变了属性,属性与反思常规无序字典而不是

private class MyTagBuilder: TagBuilder 
{ 
    private static readonly MethodInfo tagBuilderAttrSetMethod = typeof(TagBuilder).GetProperty(nameof(Attributes)).SetMethod; 

    public MyTagBuilder(string tagName) : base(tagName) 
    { 
     // TagBuilder internally uses SortedDictionary, render attributes according to the order they are added instead 
     tagBuilderAttrSetMethod.Invoke(this, new object[] { new Dictionary<string, string>() }); 
    } 
} 
相关问题