So übernehmen Sie die Kontrolle über Stylesheets in ASP.NET-Designs mit dem StylePlaceHolder- und Style-Steuerelement




css themes (2)

Ich habe die Antwort auf meine Frage gefunden.

Der Grund für die Renderfehler, die ich im Entwurfsmodus erhalte, ist ein offensichtlicher Fehler in Visual Studio SP1, den Microsoft noch beheben muss .

Der obige Code funktioniert also auch im Entwurfsmodus wie erwartet, solange Sie nur die benutzerdefinierten Steuerelemente in eine vorkompilierte Assembly und nicht durch ein anderes Projekt in derselben Lösung einfügen.

Siehe den obigen Link für eine detailliertere Erklärung, wie und warum.

Update: Dies verwandelte sich in einen Blog-Post, mit aktualisierten Links und Code, auf meinem Blog: https://egilhansen.com/2008/12/01/how-to-take-control-of-style-sheets-in- asp-net-themes-mit-dem-styleplaceholder-und-style-control /

Das Problem ist ziemlich einfach. Bei der Verwendung von ASP.NET-Designs haben Sie nicht viel Einfluss darauf, wie Ihre Stylesheets auf der Seite gerendert werden.

Die Render-Engine fügt alle Stylesheets, die Sie in Ihrem Themes-Ordner haben, in alphabetischer Reihenfolge hinzu und verwendet dabei die Schreibweise <link href = "...".

Wir alle wissen, dass die Reihenfolge der Stylesheets wichtig ist, glücklicherweise können asp.nets-Unzulänglichkeiten umgangen werden, indem man den Stylesheets 01, 02, ..., 99 vorangestellt und damit die gewünschte Reihenfolge erzwingt (siehe Rusty Swayne Blogpost auf die Technik für mehr Informationen).

Dies ist besonders wichtig, wenn Sie ein Reset-Stylesheet verwenden, das ich sehr empfehlen kann; es macht es viel einfacher, eine Website in einer konsistenten Form über Browser hinweg zu gestalten (siehe Reset Reloaded von Eric Meyer ).

Ihnen fehlt auch die Möglichkeit, einen Medientyp anzugeben (z. B. Bildschirm, Druck, Projektion, Blindenschrift, Sprache). Und wenn Sie Stylesheets mit der @ import-Methode bevorzugen, bleiben Sie auch draußen.

Eine weitere fehlende Option ist Bedingter Kommentar, was besonders nützlich ist, wenn Sie ein Stylesheet "ie-fix.css" verwenden.

Bevor ich erkläre, wie der StylePlaceholder und die Style-Kontrolle die oben genannten Probleme lösen, Kredit, wo Kredit fällig ist, ist meine Lösung von Per Zimmermans Blog-Post zu diesem Thema inspiriert.

Das StylePlaceHolder-Steuerelement wird im Kopfbereich Ihrer Masterseite oder Seite platziert. Es kann ein oder mehrere Style-Steuerelemente enthalten und entfernt Stile, die von der Render-Engine standardmäßig hinzugefügt wurden, und fügt eigene hinzu (es werden nur Stile aus dem aktuellen aktiven Design entfernt).

Das Style-Steuerelement kann sowohl Inline-Stile zwischen den öffnenden und schließenden Tags als auch einen Verweis auf eine externe Stylesheet-Datei über die CssUrl-Eigenschaft hosten. Mit anderen Eigenschaften steuern Sie, wie das Stylesheet auf der Seite dargestellt wird.

Lassen Sie mich ein Beispiel zeigen. Betrachten Sie ein einfaches Website-Projekt mit einer Masterseite und einem Theme mit drei Stylesheets - 01reset.css, 02style.css, 99iefix.cs. Hinweis: Ich habe sie mit der oben beschriebenen Präfix-Technik benannt, da sie für eine bessere Design-Zeiterfahrung sorgt. Außerdem lautet das Tag-Präfix der benutzerdefinierten Steuerelemente "ass:".

Fügen Sie im Kopfbereich der Masterseite Folgendes hinzu:

<ass:StylePlaceHolder ID="StylePlaceHolder1" runat="server" SkinID="ThemeStyles" />

Fügen Sie in Ihrem Themenverzeichnis eine Skin-Datei (z. B. Styles.skin) hinzu und fügen Sie folgenden Inhalt hinzu:

<ass:StylePlaceHolder1runat="server" SkinId="ThemeStyles">
    <ass:Style CssUrl="~/App_Themes/Default/01reset.css" />
    <ass:Style CssUrl="~/App_Themes/Default/02style.css" />
    <ass:Style CssUrl="~/App_Themes/Default/99iefix.css" ConditionCommentExpression="[if IE]" />
</ass:StylePlaceHolder1>

Das ist es im Grunde. Es gibt eine Reihe von Eigenschaften im Style-Steuerelement, die zur Steuerung des Renderings verwendet werden können. Dies ist jedoch die grundlegende Konfiguration. Damit können Sie problemlos ein anderes Design hinzufügen und alle Stile ersetzen, da Sie nur eine andere Skin-Datei hinzufügen müssen.

Nun zu dem Code, der alles möglich macht. Ich muss zugeben, dass die Designerfahrung einige Macken hat. Es ist wahrscheinlich aufgrund der Tatsache, dass ich nicht sehr geschickt benutzerdefinierte Steuerelemente zu schreiben (in der Tat, diese beiden sind meine ersten Versuche), so würde ich sehr gerne Eingabe in das folgende. In einem aktuellen WCAB / WCSF-basierten Projekt, das ich entwickle, sehe ich Fehler wie diese in der Designansicht von Visual Studios, und ich habe keine Ahnung warum. Die Seite kompiliert und alles funktioniert online.

Beispiel für einen Entwurfszeitfehler in Visual Studio http://www.egil.dk/wp-content/styleplaceholder-error.jpg

Der folgende Code ist für das StylePlaceHolder-Steuerelement:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;

[assembly: TagPrefix("Assimilated.Extensions.Web.Controls", "ass")]
namespace Assimilated.WebControls.Stylesheet
{
    [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [DefaultProperty("SkinID")]
    [ToolboxData("<{0}:StylePlaceHolder runat=\"server\" SkinID=\"ThemeStyles\"></{0}:StylePlaceHolder>")]
    [ParseChildren(true, "Styles")]
    [Themeable(true)]
    [PersistChildren(false)]
    public class StylePlaceHolder : Control
    {
        private List<Style> _styles;

        [Browsable(true)]
        [Category("Behavior")]
        [DefaultValue("ThemeStyles")]
        public override string SkinID { get; set; }

        [Browsable(false)]
        public List<Style> Styles
        {
            get
            {
                if (_styles == null)
                    _styles = new List<Style>();
                return _styles;
            }
        }

        protected override void CreateChildControls()
        {
            if (_styles == null)
                return;

            // add child controls
            Styles.ForEach(Controls.Add);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            // get notified when page has finished its load stage
            Page.LoadComplete += Page_LoadComplete;
        }

        void Page_LoadComplete(object sender, EventArgs e)
        {
            // only remove if the page is actually using themes
            if (!string.IsNullOrEmpty(Page.StyleSheetTheme) || !string.IsNullOrEmpty(Page.Theme))
            {
                // Make sure only to remove style sheets from the added by
                // the runtime form the current theme.
                var themePath = string.Format("~/App_Themes/{0}",
                                              !string.IsNullOrEmpty(Page.StyleSheetTheme)
                                                  ? Page.StyleSheetTheme
                                                  : Page.Theme);

                // find all existing stylesheets in header
                var removeCandidate = Page.Header.Controls.OfType<HtmlLink>()
                    .Where(link => link.Href.StartsWith(themePath)).ToList();

                // remove the automatically added style sheets
                removeCandidate.ForEach(Page.Header.Controls.Remove);
            }
        }

        protected override void AddParsedSubObject(object obj)
        {
            // only add Style controls
            if (obj is Style)
                base.AddParsedSubObject(obj);
        }

    }
}

Und der Code für das Style-Steuerelement:

using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;

[assembly: TagPrefix("Assimilated.Extensions.Web.Controls", "ass")]
namespace Assimilated.WebControls.Stylesheet
{
    [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [DefaultProperty("CssUrl")]
    [ParseChildren(true, "InlineStyle")]
    [PersistChildren(false)]
    [ToolboxData("<{0}:Style runat=\"server\"></{0}:Style>")]
    [Themeable(true)]
    public class Style : Control
    {
        public Style()
        {
            // set default value... for some reason the DefaultValue attribute do
            // not set this as I would have expected.
            TargetMedia = "All";
        }

        #region Properties

        [Browsable(true)]
        [Category("Style sheet")]
        [DefaultValue("")]
        [Description("The url to the style sheet.")]
        [UrlProperty("*.css")]
        public string CssUrl
        {
            get; set;
        }

        [Browsable(true)]
        [Category("Style sheet")]
        [DefaultValue("All")]
        [Description("The target media(s) of the style sheet. See http://www.w3.org/TR/REC-CSS2/media.html for more information.")]
        public string TargetMedia
        {
            get; set;
        }

        [Browsable(true)]
        [Category("Style sheet")]
        [DefaultValue(EmbedType.Link)]
        [Description("Specify how to embed the style sheet on the page.")]
        public EmbedType Type
        {
            get; set;
        }

        [Browsable(false)]
        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public string InlineStyle
        {
            get; set;
        }

        [Browsable(true)]
        [Category("Conditional comment")]
        [DefaultValue("")]
        [Description("Specifies a conditional comment expression to wrap the style sheet in. See http://msdn.microsoft.com/en-us/library/ms537512.aspx")]
        public string ConditionalCommentExpression
        {
            get; set;
        }

        [Browsable(true)]
        [Category("Conditional comment")]
        [DefaultValue(CommentType.DownlevelHidden)]
        [Description("Whether to reveal the conditional comment expression to downlevel browsers. Default is to hide. See http://msdn.microsoft.com/en-us/library/ms537512.aspx")]
        public CommentType ConditionalCommentType
        {
            get; set;
        }

        [Browsable(true)]
        [Category("Behavior")]
        public override string SkinID { get; set; }

        #endregion

        protected override void Render(HtmlTextWriter writer)
        {            
            // add empty line to make output pretty
            writer.WriteLine();

            // prints out begin condition comment tag
            if (!string.IsNullOrEmpty(ConditionalCommentExpression))
                writer.WriteLine(ConditionalCommentType == CommentType.DownlevelRevealed ? "<!{0}>" : "<!--{0}>",
                                 ConditionalCommentExpression);

            if (!string.IsNullOrEmpty(CssUrl))
            {               
                // add shared attribute
                writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/css");

                // render either import or link tag
                if (Type == EmbedType.Link)
                {
                    // <link href=\"{0}\" type=\"text/css\" rel=\"stylesheet\" media=\"{1}\" />
                    writer.AddAttribute(HtmlTextWriterAttribute.Href, ResolveUrl(CssUrl));
                    writer.AddAttribute(HtmlTextWriterAttribute.Rel, "stylesheet");
                    writer.AddAttribute("media", TargetMedia);
                    writer.RenderBeginTag(HtmlTextWriterTag.Link);
                    writer.RenderEndTag();
                }
                else
                {
                    // <style type="text/css">@import "modern.css" screen;</style>
                    writer.RenderBeginTag(HtmlTextWriterTag.Style);
                    writer.Write("@import \"{0}\" {1};", ResolveUrl(CssUrl), TargetMedia);
                    writer.RenderEndTag();
                }
            }

            if(!string.IsNullOrEmpty(InlineStyle))
            {
                // <style type="text/css">... inline style ... </style>
                writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/css");
                writer.RenderBeginTag(HtmlTextWriterTag.Style);
                writer.Write(InlineStyle);
                writer.RenderEndTag();
            }

            // prints out end condition comment tag
            if (!string.IsNullOrEmpty(ConditionalCommentExpression))
            {
                // add empty line to make output pretty
                writer.WriteLine();
                writer.WriteLine(ConditionalCommentType == CommentType.DownlevelRevealed ? "<![endif]>" : "<![endif]-->");
            }
        }
    }

    public enum EmbedType
    {        
        Link = 0,
        Import = 1,
    }

    public enum CommentType
    {
        DownlevelHidden = 0,
        DownlevelRevealed = 1
    }
}

Also, was denkst du? Ist dies eine gute Lösung für das Asp.net-Problem? Und was ist mit dem Code? Ich hätte gerne einen Input dazu, vor allem in Bezug auf die Designzeit.

Ich habe eine gezippte Version der Visual Studio-Lösung hochgeladen, die das Projekt enthält, falls jemand interessiert ist.

Mit freundlichen Grüßen, Egil.


Funktioniert sehr reibungslos.

Für diejenigen wie mich, die sich niemals an die Syntax von <% -Tags erinnern, müssen Sie hier den Anfang der Masterseitendefinition und die Skin-Datei hinzufügen, um den Namespace zu registrieren.

<%@ Register TagPrefix="ass" Namespace="Assimilated.WebControls.Stylesheet" %>

Ich bin mir nicht sicher, ob ich so viel "Arsch" über meinen Code haben möchte, aber ansonsten mag ich es.

Oh, und wenn das wirklich dein erster toller Job ist? Ich weiß, dass es von jemand anderem Code inspiriert wurde, aber es scheint zumindest die richtigen Attribute und Schnittstellen zu haben.







custom-server-controls