2008-11-30 49 views
10

Cập nhật: này biến thành một bài đăng blog, với các liên kết được cập nhật và mã, qua tại blog của tôi: https://egilhansen.com/2008/12/01/how-to-take-control-of-style-sheets-in-asp-net-themes-with-the-styleplaceholder-and-style-control/Làm thế nào để kiểm soát style sheets trong ASP.NET Chủ đề với StylePlaceHolder và Phong cách kiểm soát


Vấn đề khá đơn giản. Khi sử dụng ASP.NET Chủ đề bạn không có nhiều nói trong cách phong cách của bạn tờ được trả lại cho trang.

Công cụ hiển thị thêm tất cả các mẫu kiểu bạn có trong thư mục chủ đề của bạn theo thứ tự chữ cái, sử dụng ký hiệu < link href = ”...”.

Chúng ta đều biết thứ tự của các tờ mẫu là quan trọng, may mắn asp.nets thiếu sót có thể được circumvented bởi tiền tố phong cách tờ với 01, 02, ..., 99, và do đó buộc thứ tự bạn muốn (xem Rusty Swayne blog post về kỹ thuật này để biết thêm thông tin).

Điều này đặc biệt quan trọng nếu bạn sử dụng bảng định kiểu đặt lại, mà tôi đặc biệt khuyên dùng; nó giúp việc tạo kiểu trang web trong một biểu mẫu nhất quán dễ dàng hơn trên các trình duyệt (xem Reset Reloaded from Eric Meyer).

Bạn cũng bỏ lỡ khả năng chỉ định loại phương tiện (ví dụ: màn hình, in, chiếu, chữ nổi, lời nói). Và nếu bạn muốn bao gồm các tờ kiểu bằng cách sử dụng phương pháp @import, bạn cũng bị loại bỏ trong điều kiện lạnh.

Một tùy chọn còn thiếu khác là Nhận xét có điều kiện, đặc biệt hữu ích nếu bạn sử dụng biểu định kiểu "ie-fix.css".

Trước khi tôi giải thích cách kiểm soát StylePlaceholder và Style giải quyết các vấn đề trên, tín dụng khi tín dụng đến hạn, giải pháp của tôi được lấy cảm hứng từ Per Zimmerman’s blog post về chủ đề.

Điều khiển StylePlaceHolder được đặt trong phần tiêu đề của trang chính hoặc trang chính của bạn. Nó có thể lưu trữ một hoặc nhiều điều khiển kiểu và sẽ xóa kiểu được công cụ hiển thị thêm vào theo mặc định và thêm kiểu của riêng nó (nó sẽ chỉ xóa kiểu được thêm từ chủ đề hiện hoạt hiện tại).

Kiểm soát kiểu có thể lưu trữ kiểu nội tuyến ở giữa thẻ mở và đóng và tham chiếu đến tệp trang tính ngoài thông qua thuộc tính CssUrl của nó. Với các thuộc tính khác, bạn kiểm soát cách biểu định kiểu mà nó hiển thị cho trang.

Hãy để tôi hiển thị ví dụ. Hãy xem xét một dự án trang web đơn giản với một trang cái và một chủ đề với ba tờ định kiểu - 01reset.css, 02style.css, 99iefix.cs. Lưu ý: Tôi đã đặt tên cho chúng bằng cách sử dụng kỹ thuật tiền tố được mô tả trước đó, vì nó làm cho trải nghiệm thiết kế tốt hơn. Ngoài ra, tiền tố thẻ của các điều khiển tùy chỉnh là “ass:”.

Trong phần tiêu đề trang thạc sĩ, thêm:

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

Trong thư mục chủ đề của bạn, thêm một tập tin da (ví dụ Styles.skin) và thêm các nội dung sau đây:

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

Đó là về cơ bản nó. Có nhiều thuộc tính hơn trên điều khiển Kiểu có thể được sử dụng để kiểm soát hiển thị, nhưng đây là thiết lập cơ bản. Với điều đó tại chỗ, bạn có thể dễ dàng thêm một chủ đề khác và thay thế tất cả các kiểu, vì bạn chỉ cần bao gồm một tệp da khác.

Bây giờ đến mã khiến mọi thứ xảy ra. Tôi phải thừa nhận rằng kinh nghiệm thiết kế thời gian có một số quirks.Có lẽ là do tôi không thành thạo trong việc viết các điều khiển tùy chỉnh (trên thực tế, hai điều này là những nỗ lực đầu tiên của tôi), vì vậy tôi rất thích đầu vào như sau. Trong một dự án WCAB/WCSF hiện tại tôi đang phát triển, tôi thấy lỗi như thế này trong quan điểm thiết kế của Visual Studios, và tôi không biết tại sao. Trang web biên dịch và mọi thứ hoạt động trực tuyến.

Example of design time error in Visual Studio http://www.egil.dk/wp-content/styleplaceholder-error.jpg

Sau đây là mã cho sự kiểm soát 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); 
     } 

    } 
} 

Và mã cho điều khiển Kiểu:

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

Vậy điều gì làm bạn nghĩ? Đây có phải là một giải pháp tốt cho vấn đề chủ đề asp.net? Và những gì về mã? Tôi thực sự muốn một số đầu vào vào nó, đặc biệt là liên quan đến kinh nghiệm thời gian thiết kế.

Tôi đã tải lên zipped version of the Visual Studio solution có chứa dự án, trong trường hợp ai đó quan tâm.

Trân trọng, Egil.

Trả lời

2

Tìm câu trả lời cho câu hỏi của riêng tôi.

Lý do cho lỗi hiển thị mà tôi nhận được trong chế độ thiết kế, là một lỗi rõ ràng trong Visual Studio SP1, which Microsoft has yet to fix.

Vì vậy, mã trên hoạt động như mong đợi, cũng ở chế độ thiết kế, miễn là bạn chỉ bao gồm các điều khiển tùy chỉnh trong một bản được biên dịch trước và không thông qua một dự án khác trong cùng một giải pháp.

Xem liên kết ở trên để biết giải thích chi tiết hơn về cách thức và lý do.

0

Hoạt động rất suôn sẻ.

Đối với những người như tôi không bao giờ nhớ cú pháp của <% thẻ dưới đây là những gì bạn cần thêm vào đầu định nghĩa trang chính và tệp da để đăng ký không gian tên.

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

Tôi không chắc mình muốn nhiều 'ass' trên mã của mình, nhưng nếu không thì tôi thích nó.

Oh và nếu đây thực sự là công việc tuyệt vời đầu tiên của bạn, hãy kiểm soát tùy chỉnh. Tôi biết nó được lấy cảm hứng từ mã của người khác nhưng ít nhất là xuất hiện để có tất cả các thuộc tính và giao diện phù hợp.

+0

Cảm ơn các từ loại Simon. Điều này thực sự là điều khiển tùy chỉnh đầu tiên của tôi, nó đã được tái cấu trúc một vài lần ngay bây giờ, vì vậy điều khiển tùy chỉnh đầu tiên, không phải lần đầu tiên :) –

+0

@egil điều buồn cười là tôi chuyển sang MVC ngày hôm sau - một phần vì tôi đã mệt mỏi phải đi tìm các giải pháp thông minh như của bạn cho những vấn đề đơn giản. may mắn thay tôi đang phát triển một trang web mới vì vậy tôi đã được phép sang trọng để chơi với MVC và tôi thực sự thích nó –

0

Re: sử dụng tệp CSS phương tiện cụ thể, bạn có thể sử dụng câu lệnh @media CSS, hoạt động tốt.

Các vấn đề liên quan