StylePlaceHolderおよびStyleコントロールを使用してASP.NETテーマのスタイルシートを制御する方法

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

質問

更新:これは、私のブログのリンクとコードが更新されたブログ投稿になりました: https://egilhansen.com/2008 / 12/01 / asp-net-the-styles-with-the-style-place-holder-and-style-control /

のスタイルシートのコントロールの取得方法

問題は非常に単純です。 ASP.NETテーマを使用する場合、スタイルシートがどのようにページにレンダリングされるかについてはあまり言及していません。

レンダリングエンジンは、<!> lt; link href = <!>#8221; ... <!>#8221;を使用して、テーマフォルダーにあるすべてのスタイルシートをアルファベット順に追加します。表記法。

スタイルシートの順序が重要であることは誰もが知っていますが、幸いなことにasp.netsの欠点は、スタイルシートの先頭に01、02、...、99を付けて、必要な順序を強制することで回避できます(Rusty Swayne詳細については、ブログ投稿をご覧ください)。

これは、リセットスタイルシートを使用する場合に特に重要です。ブラウザ間で一貫した形式のサイトのスタイル設定がはるかに簡単になります( Eric Meyerからリロードされたリセット)。

メディアタイプ(スクリーン、印刷、投影、点字、音声など)を指定することもできません。また、@ importメソッドを使用してスタイルシートを含めることを希望する場合は、寒さの中に取り残されます。

もう1つの欠落しているオプションは条件付きコメントです。これは、<!>#8220; ie-fix.css <!>#8221;を使用する場合に特に便利です。スタイルシート。

StylePlaceholderとStyleコントロールが上記の問題を解決する方法を説明する前に、クレジットの期限が来るクレジットについて、私の解決策は Per Zimmerman <!>#8217; sのブログ投稿件名。

StylePlaceHolderコントロールは、マスターページまたはページのヘッダーセクションに配置されます。 1つ以上のスタイルコントロールをホストでき、デフォルトでレンダリングエンジンによって追加されたスタイルを削除し、独自に追加します(現在アクティブなテーマから追加されたスタイルのみを削除します)。

スタイルコントロールは、その間にあるインラインスタイルをホストできます<!>#8217; sの開始タグと終了タグ、およびCssUrlプロパティを介した外部スタイルシートファイルへの参照。他のプロパティを使用して、スタイルシートをページにレンダリングする方法を制御します。

例を示します。マスターページと3つのスタイルシートを持つテーマを備えた単純なWebサイトプロジェクトを考えてみましょう<!>#8211; 01reset.css、02style.css、99iefix.cs。注:デザイン時のエクスペリエンスを向上させるため、前述のプレフィックス手法を使用して名前を付けました。また、カスタムコントロールのタグプレフィックスは<!>#8220; ass:<!>#8221;です。

マスターページ<!>#8217;のヘッダーセクションに、以下を追加します。

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

テーマディレクトリで、スキンファイル(Styles.skinなど)を追加し、次のコンテンツを追加します:

<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>

それは基本的にそれです。 Styleコントロールには、レンダリングの制御に使用できるプロパティがありますが、これは基本的なセットアップです。別のスキンファイルをインクルードするだけでよいため、これを配置すると、別のテーマを簡単に追加し、すべてのスタイルを置き換えることができます。

すべてを実現するコードについて説明します。設計時の経験にはいくつかの癖があることを認めなければなりません。おそらく、私がカスタムコントロールの作成にあまり精通していないという事実(実際、これら2つは私の最初の試みです)であるため、次の入力を非常に希望します。現在開発中のWCAB / WCSFベースのプロジェクトでは、Visual Studioのデザインビューでこのようなエラーが表示されます。nd理由がわかりません。サイトがコンパイルされ、すべてがオンラインで動作します。

Visual Studioでの設計時エラーの例http://www.egil .dk / wp-content / styleplaceholder-error.jpg

StylePlaceHolderコントロールのコードは次のとおりです。

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

    }
}

そして、スタイルコントロールのコード:

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

では、皆さんはどう思いますか?これはasp.netテーマの問題の良い解決策ですか?そして、コードはどうですか?特に設計時の経験に関して、私はそれについていくつかの入力が本当に欲しいです。

zipバージョンのVisual Studioソリューション誰でも興味がある場合に備えて、プロジェクトが含まれています。

よろしく、エギル。

役に立ちましたか?

解決

自分の質問に対する答えを見つけました。

デザインモードでレンダリングエラーが発生する理由は、Visual Studio SP1の明らかなバグ Microsoftがまだ修正していない

上記のコードは、同じソリューションの別のプロジェクトではなく、事前にコンパイルされたアセンブリにカスタムコントロールを含めるだけである限り、デザインモードでも期待どおりに機能します。

方法と理由の詳細な説明については、上記のリンクを参照してください。

他のヒント

非常にスムーズに動作します。

<!> lt;%タグの構文を決して覚えていない私のような人のために、名前空間を登録するためにマスターページ定義とスキンファイルの先頭に追加する必要があるものがここにあります。

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

コード全体にそんなに「お尻」が欲しいかどうかはわかりませんが、そうでなければ好きです。

ああ、これが本当に最初のカスタムコントロールの素晴らしい仕事なら。他の人のコードに触発されたのは知っていますが、少なくともすべての適切な属性とインターフェースを備えているように見えます

再:特定のメディアCSSファイルを使用すると、@ media CSSステートメントを使用できます。正常に動作します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top