Update: Dies in eine Blog-Post gedreht, mit aktualisierten Links und Code, über auf meinem Blog: https://egilhansen.com/2008/12/01/how-to-take-control-of-style-sheets-in-asp-net-themes-with-the-styleplaceholder-and-style-control/Wie mit dem Styleplaceholder und Style-Kontrolle in ASP.NET Themen Kontrolle von Stylesheets nehmen
Das Problem ist ziemlich einfach. Bei der Verwendung von ASP.NET-Designs haben Sie nicht viel zu sagen, 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, indem Sie die < link href = "..." -Notation verwenden.
Wir alle wissen, dass die Reihenfolge der Stylesheets wichtig ist, glücklicherweise können asp.nets - Unzulänglichkeiten umgangen werden, indem man die Stylesheets mit 01, 02, ..., 99 voranstellt und so die gewünschte Reihenfolge erzwingt (siehe Rusty Swayne blog post auf die Technik für weitere Informationen).
Dies ist besonders wichtig, wenn Sie ein Reset-Stylesheet verwenden, das ich sehr empfehlen kann; es macht es viel einfacher, eine Website in konsistenter Form über Browser hinweg zu gestalten (siehe Reset Reloaded from 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 die StylePlaceholder und Style-Kontrolle die oben genannten Probleme lösen, Kredit, wo Kredit fällig ist, ist meine Lösung von Per Zimmerman’s blog post zum 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:".
im Kopfbereich der Master-Seite hinzufügen:
<ass:StylePlaceHolder ID="StylePlaceHolder1" runat="server" SkinID="ThemeStyles" />
In Ihrem Themenverzeichnis, fügen Sie eine Skin-Datei (zB Styles.skin) und den 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 heißt im Grunde genommen. 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 Eingang in die folgenden. 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.
Im Folgenden ist der Code für die Steuerung 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);
}
}
}
Und der Code für die Style-Steuerung:
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 denkt ihr? 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 zipped version of the Visual Studio solution hochgeladen, die das Projekt enthält, falls jemand interessiert ist.
Mit freundlichen Grüßen, Egil.
Danke für die freundlichen Worte Simon. Dies ist in der Tat meine erste benutzerdefinierte Kontrolle, es wurde jedoch einige Male umgestaltet, so erste benutzerdefinierte Steuerung, nicht der erste Versuch :) –
@egil lustige Sache ist ich am nächsten Tag zu MVC gewechselt - teilweise weil ich müde wurde Sie müssen nach cleveren Lösungen wie Ihren nach einfachen Problemen suchen. glücklicherweise entwickle ich eine neue Seite, also durfte ich den Luxus mit MVC spielen und genieße es wirklich –