简体   繁体   English

你能控制 TagBuilder 类呈现属性的顺序吗?

[英]Can you control the order in which the TagBuilder class renders attributes?

I know this is kind of obsessive, but is there a way to control the order that the TagBuilder class renders the attributes of an HTML tag when you call ToString() ?我知道这有点强迫症,但是有没有一种方法可以控制TagBuilder类在您调用ToString()时呈现 HTML 标记属性的顺序?

ie so that即这样

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)

will return将返回

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

not不是

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

Changing the order that you add the attributes doesn't change it, it seems to be rendering in alphabetical order更改添加属性的顺序不会改变它,它似乎是按字母顺序呈现的

Try using this class, which inherits the TagBuilder and overrides the ToString method, building a SortedDictionary from the Attributes and using that dictionary to render.尝试使用此类继承 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();
        }
    }

I disassembled TagBuilder.ToString() with Reflector, and this is the key bit of code:我用 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 });
}

So I would say not - this.Attributes is an IDictionary<string,string> interface, when enumerating over that "the order in which the items are returned is undefined," according to MSDN.所以我会说不是 - this.Attributes是一个IDictionary<string,string>接口,根据 MSDN 的说法,当枚举“返回项目的顺序是未定义的”时。

I did not want to override all that code to modify the sort behaviour so I changed the Attributes-property to a regular unsorted Dictionary with reflection instead我不想覆盖所有代码来修改排序行为,所以我将 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.

相关问题 TagBuilder AddCssClass顺序,添加到开头,如何在结尾添加新类? - TagBuilder AddCssClass Order, Adds to Beginning, how to Add New Class at the End? 你能改变 RenderSection 的执行顺序吗? - Can you change the order in which RenderSection executes? 将属性添加到控件类 - Add attributes to a control class 如何在类库项目中使用TagBuilder? - How to use TagBuilder in a Class Library project? Net Core:是否可以将TagBuilder样式属性与CSS文件合并? - Net Core: Is it Possible to Merge TagBuilder Style Attributes with CSS Files? C#给定自定义类和自定义属性,如何从基类中找到类的属性 - C# Given a custom class and custom attribute how can you find the attributes of a class from the base class 如果您无法控制 class,您如何模拟 class 中的方法? - How can you mock the methods from a class if you have no control over the class? 给定一个XML文档,如何遵循XML文档的顺序列出所有属性和元素 - Given an XML document, how can you list all attributes and elements obeying the order of the xml document 在可以修改的类上使用扩展方法是否可以接受 - Is it acceptable to use extension methods on a class which you can modify 如何在不使用 class 映射的情况下控制 CsvHelper 写入 CSV 文件头的顺序? - How to control the order in which CSV file headers are written by CsvHelper without using a class a mapping?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM