2010-10-06 39 views
10

Sự cố: Tôi đang nhúng tệp CSS vào thư viện điều khiển tùy chỉnh với một số điều khiển. Tôi muốn chia sẻ cùng một tệp CSS cho tất cả các điều khiển bất kể có bao nhiêu phiên bản của chúng trên một biểu mẫu nhất định. Khi có nhiều hơn một điều khiển trên biểu mẫu, tôi muốn chính xác 1 tham chiếu đến tệp CSS trong tiêu đề HTML của trang ASP.NET.Kiểm soát tùy chỉnh ASP.NET - Cách tốt nhất để bao gồm tham chiếu CSS nhúng chỉ một lần là gì?

Dưới đây là những gì tôi đã đưa ra (cho đến nay):

Public Sub IncludeStyles(ByVal Page As System.Web.UI.Page) 
    'Don't include the reference if it already exists... 
    If Page.Header.FindControl("MyID") Is Nothing Then 
     Dim cssUrl As String = Page.ClientScript.GetWebResourceUrl(GetType(Common), StylePath) 

     Dim css As New System.Web.UI.HtmlControls.HtmlGenericControl("link") 
     With css 
      .Attributes.Add("rel", "stylesheet") 
      .Attributes.Add("type", "text/css") 
      .Attributes.Add("href", cssUrl) 
      .ID = "MyID" 
     End With 

     Page.Header.Controls.Add(css) 
    End If 
End Sub 

Ok, nó hoạt động ... nhưng lỗ hổng rõ ràng ở đây là việc sử dụng FindControl() để xem nếu việc kiểm soát tồn tại trên hình thức . Mặc dù tôi đang sử dụng các thùng chứa đặt tên và nó vẫn có vẻ hoạt động, tôi chắc chắn có một số cách để phá vỡ điều này. Việc thêm một điều khiển khác vào biểu mẫu có cùng ID chắc chắn là một ...

Câu hỏi: Cách tốt hơn để đảm bảo kiểm soát tiêu đề chỉ được thêm vào tiêu đề HTML chính xác một lần là gì?

Lưu ý: Phương thức ClientScript.RegisterClientScriptResource() có tham số chấp nhận loại .NET và loại này có thể được sử dụng để đảm bảo mã chỉ xuất mỗi lần trên một trang. Rất tiếc, phương thức này chỉ hoạt động với các tham chiếu tệp JavaScript. Nếu có một tương đương được xây dựng trong cho tài liệu tham khảo CSS, đó sẽ là sở thích của tôi.

Cập nhật:

tôi phát hiện ra một cách nhẹ thanh lịch hơn để làm điều này bằng cách sử dụng here Page.ClientScript.RegisterClientScriptBlock và nói với nó, bạn được bao gồm các thẻ script riêng của bạn, tuy nhiên như Rick chỉ ra, điều này doesn' t thêm tập lệnh vào thẻ đầu html và cũng không tương thích với xhtml.

Cập nhật 2:

tôi thấy một ý tưởng thú vị về this thread, nhưng vòng lặp thông qua bộ sưu tập các điều khiển không phải là một giải pháp rất tốt và cho biết thêm rất nhiều chi phí nếu bạn có nhiều tài liệu tham khảo và một số điều khiển trên trang .

Chris Sống động với giải pháp tốt hơn yêu cầu ít mã hơn. Đây là chức năng của tôi được thay đổi bằng giải pháp mới:

Public Sub IncludeStyles(ByVal Page As System.Web.UI.Page) 
    If Not Page.ClientScript.IsClientScriptBlockRegistered(StyleName) Then 
     Dim cssUrl As String = Page.ClientScript.GetWebResourceUrl(GetType(Common), StylePath) 

     Dim css As New System.Web.UI.HtmlControls.HtmlGenericControl("link") 
     With css 
      .Attributes.Add("href", cssUrl) 
      .Attributes.Add("rel", "stylesheet") 
      .Attributes.Add("type", "text/css") 
     End With 

     Page.Header.Controls.Add(css) 
     Page.ClientScript.RegisterClientScriptBlock(GetType(Page), StyleName, "") 
    End If 
End Sub 

Một vài điều cần lưu ý về giải pháp này. Trong bài đăng gốc của mình, Chris đã sử dụng phương thức IsClientScriptIncludeRegistered() không phải là phương pháp tương ứng với phương thức RegisterClientScriptBlock(). Để thực hiện chức năng này một cách chính xác, thử nghiệm phải được thực hiện với IsClientScriptBlockRegistered().

Ngoài ra, hãy chú ý cẩn thận đến loại được chuyển đến RegisterClientScriptBlock(). Tôi đã thông qua một kiểu dữ liệu tùy chỉnh cho phương thức này (giống nhau trên tất cả các điều khiển của tôi), nhưng nó không đăng ký theo cách mà thử nghiệm IsClientScriptBlockRegistered() sẽ hoạt động. Để cho nó hoạt động, đối tượng Trang hiện tại phải được chuyển thành đối số Type.

Mặc dù phải thừa nhận rằng giải pháp này hơi giống như hack, a) không yêu cầu nhiều mã hoặc phí, b) tạo ra chính xác kết quả mong muốn trên trang và c) là mã tuân thủ xhtml.

+0

Về mặt lý thuyết, tại sao là css không nằm trong tập tin css chính của trang web đó được nạp và lưu trữ của khách hàng? – jball

+2

Đây là thư viện điều khiển có thể được sử dụng trong bất kỳ trang web nào và tôi thích sử dụng một CSS riêng biệt (có thể dễ dàng bị ghi đè) thay vì mã hóa cứng tất cả nội tuyến CSS (như Microsoft đã làm trong nhiều trường hợp). Nói cách khác, các điều khiển của tôi hoàn toàn không biết về trang web mà chúng được lưu trữ trong. – NightOwl888

+0

Trình dịch vụ w3validator không thích ampersand chưa mã hóa mà GetWebResourceUrl trả về. Để khắc phục mã hóa url bằng Page.Server.HtmlEncode (url) – daniatic

Trả lời

9

Để tránh trùng lặp khi phát các file css từ điều khiển máy chủ, chúng ta thực hiện như sau:

if (!Page.ClientScript.IsClientScriptBlockRegistered("SoPro." + id)) { 
    HtmlLink cssLink = new HtmlLink(); 
    cssLink.Href = cssLink.Href = Page.ClientScript.GetWebResourceUrl(this.GetType(), styleSheet); 
    cssLink.Attributes.Add("rel", "stylesheet"); 
    cssLink.Attributes.Add("type", "text/css"); 
    this.Page.Header.Controls.Add(cssLink); 
    this.Page.ClientScript.RegisterClientScriptBlock(typeof(System.Web.UI.Page), "SoPro." + id, String.Empty); 
} 

Đầu tiên chúng tôi thử nghiệm để xem nếu tập lệnh được đặt tên trước đây đã được đăng ký. Nếu không, chúng tôi thêm nó vào.

+0

Ý tưởng thú vị, và lúc đầu tôi nghĩ rằng nó sẽ làm việc. Tuy nhiên, tôi đã thử nó và có một vài vấn đề (trừ khi tôi đã bỏ lỡ một cái gì đó). Điều này đăng ký CSS theo loại mime "text/javascript". Ngoài ra, nó tạo thẻ "tập lệnh" thay vì thẻ "liên kết". Thứ ba, trong khi không phải là lớn của một thỏa thuận, thẻ không được bao gồm trong phần đầu của tài liệu. – NightOwl888

+0

Rất tiếc. Đoạn mã sai. Nhìn lại. – NotMe

+0

Ý tưởng tuyệt vời! Tôi đã thêm một phiên bản sửa lỗi này vào bài đăng gốc của mình. Thử nghiệm phải được thực hiện với RegisterClientScriptBlockInclude, nhưng khác với mã này hoạt động tốt. – NightOwl888

0

Tại sao không chỉ tạo biến boolean riêng trong điều khiển mà bạn đặt thành true khi CSS được tạo ban đầu. Sau đó bạn có thể kiểm tra điều này khi phương thức được gọi để xem liệu css đã được thiết lập chưa.Ví dụ dưới đây (VB của tôi là Rusty rất có thể là sai slighty)

Private _hasCss As Boolean = False 

Public Sub IncludeStyles(ByVal Page As System.Web.UI.Page) 
    'Don't include the reference if it already exists... 
    If Not _hasCss Then 
     Dim cssUrl As String = Page.ClientScript.GetWebResourceUrl(GetType(Common), StylePath) 

     Dim css As New System.Web.UI.HtmlControls.HtmlGenericControl("link") 
     With css 
      .Attributes.Add("rel", "stylesheet") 
      .Attributes.Add("type", "text/css") 
      .Attributes.Add("href", cssUrl) 
      .ID = "MyID" 
     End With 

     Page.Header.Controls.Add(css) 
     _hasCss = True 

    End If 
End Sub 
+0

Sẽ không hoạt động. Đối với một, bạn tạo biến riêng tư - nghĩa là mỗi cá thể điều khiển sẽ có một bản sao riêng biệt. Biến được chia sẻ có khả năng sẽ có vấn đề giữa những người dùng khác nhau, do đó sẽ không hoạt động. – NightOwl888

+0

Bạn đúng NightOwl, tôi hoàn toàn bỏ lỡ điều đó! – WDuffy

3

Tôi không biết tại sao, nhưng giải pháp của bạn không hiệu quả đối với tôi, lệnh gọi ClientScript.IsClientScriptBlockRegistered luôn trả về false. Nhưng đề nghị John Bledsoe về liên kết mà bạn đã cung cấp (here) làm việc cho tôi:

public static void IncludeStylesheet(Page page, string href, string styleID) 
{ 
    //Prevent the stylesheet being included more than once 
    styleID = "_" + styleID; 
    if (HttpContext.Current.Items[styleID] == null) 
    { 
     HtmlLink htmlLink = new HtmlLink(); 
     htmlLink.Href = href; 
     htmlLink.Attributes.Add("rel", "stylesheet"); 
     htmlLink.Attributes.Add("type", "text/css"); 
     page.Header.Controls.Add(htmlLink); 
     HttpContext.Current.Items[styleID] = true; 
    } 
} 
+0

Đây là một ý tưởng thú vị là tốt. Không chắc chắn lý do tại sao tôi đã không nghĩ đến việc sử dụng HttpContext.Items trước. Nhưng cảm ơn bạn đã chia sẻ. – NightOwl888

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