Pouvez-vous contrôler l'ordre dans lequel les attributs rendent classe TagBuilder?

StackOverflow https://stackoverflow.com/questions/3465460

  •  27-09-2019
  •  | 
  •  

Question

Je sais que ce genre est obsessionnel, mais est-il un moyen de contrôler l'ordre que la classe TagBuilder rend les attributs d'une balise HTML lorsque vous appelez ToString()?

i.e.. de sorte que

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)

renverra

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

pas

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

Modification de l'ordre que vous ajoutez les attributs ne change pas, il semble être rendu dans l'ordre alphabétique

Était-ce utile?

La solution

Essayez d'utiliser cette classe, qui hérite de la TagBuilder et remplace la méthode ToString, la construction d'un SortedDictionary des attributs et en utilisant ce dictionnaire pour rendre.

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

Autres conseils

Je démonte TagBuilder.ToString() avec réflecteur, ce qui est le bit clé de code:

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

Je dirais donc pas - this.Attributes est une interface IDictionary<string,string>, quand sur cette énumération « l'ordre dans lequel les articles sont retournés n'est pas défini », selon MSDN.

Je ne voulais pas passer outre tout ce code pour modifier le comportement de tri alors j'ai changé les attributs-propriété à un dictionnaire régulier avec la réflexion au lieu Unsorted

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>() });
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top