Como assumir o controle de folhas de estilo em Temas ASP.NET com o espaço reservado Estilo e controle Estilo

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

Pergunta

Update: Isto se transformou em um post de blog, com links e código atualizado, mais no meu blog: https://egilhansen.com/2008 / 12/01 /-to take como-controle-de-folhas de estilo-em-asp-net-temas-com-o-StylePlaceHolder-e-style-control /


O problema é bastante simples. Ao usar temas ASP.NET você não tem muito a dizer na forma como suas folhas de estilo são prestados à página.

O mecanismo de renderização acrescenta todas as folhas de estilo que você tem em seus temas pasta em ordem alfabética, usando o

Todos nós sabemos a ordem das folhas de estilo são importantes, felizmente asp.nets deficiências podem ser contornadas por prefixar as folhas de estilo com 01, 02, ..., 99, e forçando assim a ordem desejada (veja Rusty Swayne blogue post sobre a técnica para mais informações).

Isto é especialmente importante se você usar uma folha de estilo de reset, que eu recomendo; torna-se muito mais fácil ao estilo de um site de forma consistente em todos os navegadores (dar uma olhada em Redefinir Reloaded de Eric Meyer ).

Você também perder a possibilidade de especificar um tipo de mídia (por exemplo, tela, impressão, projeção, braille, fala). E se você prefere para incluir folhas de estilo usando o método @import, também são deixados de fora no frio.

Outra opção que falta é Comentário Condicional, que é especialmente útil se você usar uma folha de estilo “ie-fix.css”.

Antes de me explicar como o StylePlaceHolder e estilo de controle resolver os problemas acima, o crédito onde o crédito é devido, a minha solução é inspirado blog de Per Zimmerman sobre o assunto.

O controle StylePlaceHolder é colocado na seção de cabeçalho de sua página principal ou página. Ele pode hospedar um ou mais Estilo controles, e irá remover estilos adicionados pelo mecanismo de renderização por padrão, e adicione seu próprio (ele só irá remover estilos adicionados a partir da corrente tema ativo).

O controle estilo pode ambos os estilos inline de acolhimento em-entre-lo de tags de abertura e fechamento e uma referência para um arquivo de folha de estilo externa através de sua propriedade CssUrl. Com outras propriedades que você controle como a folha de estilo que presta à página.

Deixe-me mostrar um exemplo. Considere um projeto web site simples com uma página mestra e um tema com folhas de três estilo - 01reset.css, 02style.css, 99iefix.cs. Nota: Eu chamei-os utilizando a técnica de prefixo descrito anteriormente, uma vez que contribui para uma melhor experiência de tempo de design. Além disso, o prefixo tag dos controles personalizados é “burro”.

Na seção de cabeçalho da página mestra, acrescente:

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

Em seu diretório do tema, adicionar um arquivo de pele (por exemplo Styles.skin) e adicione o seguinte conteúdo:

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

É basicamente isso. Existem mais propriedades no controle estilo que pode ser usado para controlar a prestação, mas esta é a configuração básica. Com isso no lugar, você pode facilmente adicionar um outro tema e substituir todos os estilos, desde que você só precisa incluir um arquivo de pele diferente.

Agora, para o código que faz tudo acontecer. Devo admitir que a experiência tempo de design tem algumas peculiaridades. É provavelmente devido ao fato de que eu não sou muito proficiente em escrever controles personalizados (na verdade, estes dois são minhas primeiras tentativas), então eu gostaria muito de entrada no seguinte. Em um projeto atual com base WCAB / WCSF estou desenvolvendo, estou vendo erros como este no Visual exibição de design Studios, e eu não tenho idéia do porquê. As compilações de sites e tudofunciona online.

Exemplo de erro de tempo de design no Visual Studio http: //www.egil .dk / wp-content / StylePlaceHolder-error.jpg

A seguir está o código para o controle 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);
        }

    }
}

E o código para o controle Estilo:

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

Então, o que vocês acham? Será esta uma boa solução para o problema tema asp.net? E o que acontece com o código? Eu realmente gostaria de algumas informações sobre ele, especialmente no que diz respeito à experiência de tempo de design.

Fiz upload de um zipado versão da solução Visual Studio que contém o projeto, caso alguém estiver interessado.

Com os melhores cumprimentos, Egil.

Foi útil?

Solução

Encontrou a resposta à minha pergunta.

A razão para os erros de renderização eu estou ficando no modo de design, é um aparente bug no Visual Studio SP1, que Microsoft ainda tem de correção .

Assim, o código acima funciona como esperado, também no modo de design, contanto que você incluir apenas os controles personalizados em um pré compilado montagem, e não através de outro projeto na mesma solução.

Veja o link acima para uma explicação mais detalhada de como e porquê.

Outras dicas

Obras muito bem.

Para aqueles como eu que nunca me lembro sintaxe de <% Tag aqui está o que você precisa adicionar ao topo da definição da página principal e o arquivo de pele para registrar o namespace.

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

Eu não tenho certeza que eu quero que 'ass' muito por todo o meu código, mas por outro lado eu gosto.

Ah, e se este é realmente o seu primeiro controle personalizado grande trabalho. Eu sei que foi inspirado por alguém do código, mas ele pelo menos aparece para ter todos os atributos e interfaces adequadas.

Re:. Utilizando arquivo de mídia CSS específico, você pode usar a instrução @media CSS, bem funciona

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top