![](/img/trans.png)
[英]TagBuilder AddCssClass Order, Adds to Beginning, how to Add New Class at the End?
[英]Can you control the order in which the TagBuilder class renders attributes?
我知道这有点强迫症,但是有没有一种方法可以控制TagBuilder
类在您调用ToString()
时呈现 HTML 标记属性的顺序?
即这样
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" />
更改添加属性的顺序不会改变它,它似乎是按字母顺序呈现的
尝试使用此类继承 TagBuilder 并覆盖 ToString 方法,从属性构建 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();
}
}
我用 Reflector 反汇编了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.Attributes
是一个IDictionary<string,string>
接口,根据 MSDN 的说法,当枚举“返回项目的顺序是未定义的”时。
我不想覆盖所有代码来修改排序行为,所以我将 Attributes-property 更改为带有反射的常规未排序字典
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>() });
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.