It looks like the .NET community in general has not picked up on CSS compilers. In searching Google I've not found anything even remotely relevant.
Has anyone that is using ASP.NET MVC figured out a scheme to more intelligently generate their CSS? I'd love to be able to run my CSS through Razor for example, or for SASS to get ported over or what have you. Maybe I have a new side project on my hands :)
I'd love to be able to run my CSS through Razor
What stops you?
public class CssViewResult : PartialViewResult
{
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = "text/css";
base.ExecuteResult(context);
}
}
public class HomeController : Controller
{
public ActionResult Index()
{
return new CssViewResult();
}
}
and in ~/Views/Home/Index.cshtml:
#{
var color = "White";
if (DateTime.Now.Hour > 18 || DateTime.Now.Hour < 8)
{
color = "Black";
}
}
.foo {
color: #color;
}
Now all that's left is to include it:
<link href="#Url.Action("index")" rel="stylesheet" type="text/css" />
You can also make the template strongly typed to a view model, write loops, ifs, inclusions, ...
A slight modification of #darin-dimitrov's answer. This adds the ability to pass in a model to the CssView:
public class CssViewResult : PartialViewResult
{
public CssViewResult()
{
}
public CssViewResult(object model)
{
if (model != null)
{
ViewData.Model = model;
}
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = "text/css";
base.ExecuteResult(context);
}
}
and then you just consume it with:
return new CssViewResult(model);
Phil Haack has made a blog post about LessCSS and .net:
http://haacked.com/archive/2009/12/02/t4-template-for-less-css.aspx
I know this is an old thread, I am fairly new to ASP.NET.
Working with ASP.NET Core, I am trying to use #Darin Dimitrov's answer to allow me to set custom styles using data from an external API. To the OP's question, I know you said "Dynamic" but it seems as though you really want "Compiled". I am looking for "Dynamic".
It appears the technique of returning a partial view with response type text/css works pretty well for this solution. However, the syntax used here does not work for me in ASP.NET Core 3.1. Here is the solution I used:
Instead of HomeController I am using ThemeController as it is relevant to me.
In ThemeController.cs
public async Task<IActionResult> Index()
{
var colors = await _apiService.GetThemeColors();
Response.ContentType = "text/css";
return PartialView(colors);
}
In the view ~/Views/Theme/Index.cshtml
#model ThemeColors
#{
var color = Model.primaryColor;
}
.btn-primary {
background-color: #color;
}
And then in my _Layout.cshtml
<link href="#Url.Action("Index", "Theme")" rel="stylesheet" type="text/css" />
I hope this helps someone, if anyone who is more knowledgeable around this topic can point to more relevant resources that would be greatly appreciated.
I'm using ASP.NET MVC 4, Adding ContentType="text/css" to the page directive works for me.
Posting below solution hoping that might help someone, not sure if this is best way to implement.
I had to populate input elements dynamically inside one of the tables column field, so i had to set css position field dynamically while looping through data.
Here is the code snippet,
<td>
<label>Extract Values</label>
#{ int topPostn = 20; string topPs;}
<div style="position:relative">
#foreach (var extracts in ViewData["excode"] as List<ExtractCode>)
{
topPostn += 25;
topPs = (topPostn).ToString() + "px";
<span style="position: absolute; top: #topPs" >
<input class="ag-checkbox-input" type="checkbox" id="someid" value="#extracts.value" name="xyz" aria-label="Toggle Row Selection">#extracts.displayName
</span>
}
#{ topPostn = 20; topPs = "";}
</div>
<td>
Related
I'm retrieving statistics information from the database in the form and shape of <script> tags for all my Views, some of which will go in the <head>, others in the <body>.
Some of this information is shared by all Views, like Google Analytics but other information is specific to certain Views only like order details which is only available in the Order Confirmation View.
The end result must be:
<head>
<script><!-- Google Analytics --></script>
</head>
I am using named sections in the Layout to achieve what I want:
<head>
#RenderSection("headScripts", required: false)
</head>
<body>
#RenderSection("bodyScripts", required: false)
</body>
A sample View code is:
#if ((Model.Scripts.Head != null) && (Model.Scripts.Head.Count() != 0))
{
<text>
#section headScripts
{
#foreach (var script in Model.Scripts.Head)
{
#Html.Raw(#script.Code);
}
}
</text>
}
All view models are inheriting from a base class with the Scripts field and the code I pasted above is replicated in all my views, which is a problem.
I tried to move the code to a PartialView, starting with this line right below the </body> in my Layout:
#{Html.RenderAction("Index", "Scripts");}
And in my ScriptsController:
public ActionResult Index()
{
Scripts scripts = new Scripts();
scripts.Head = whatever comes from the database;
scripts.Body = whatever comes from the database;
return PartialView("/Views/Shared/scripts.cshtml", scripts);
}
Everything worked, the Model is correctly populated and available in the scripts Partial View but unfortunately #section cannot be called in a PartialView so the <script> tags are not displayed.
Any workaround to have #if ((Model.Scripts.Head != null) && (Model.Scripts.Head.Count() != 0)) and the rest of the code in one common place used by all Views?
Maybe do it like this
<head>
#RenderSection("headScripts", required: false)
#Html.RenderAction("HeadScripts", "Scripts")
</head>
<body>
#RenderSection("bodyScripts", required: false)
#Html.RenderAction("BodyScripts", "Scripts")
</body>
Then in your scripts controller you would have two methods for each call
public ActionResult HeadScripts()
{
Scripts scripts = new Scripts();
scripts.Head = whatever comes from the database;
return PartialView("/Views/Shared/scripts.cshtml", scripts);
}
public ActionResult BodyScripts()
{
Scripts scripts = new Scripts();
scripts.Body = whatever comes from the database;
return PartialView("/Views/Shared/scripts.cshtml", scripts);
}
Hope this helps
EDIT:
Also in the PartialView you won't need the #section anymore.
#if ((Model.Scripts.Head != null) && (Model.Scripts.Head.Count() != 0))
{
#foreach (var script in Model.Scripts.Head)
{
#Html.Raw(#script.Code);
}
}
EDIT 2:
Using a BaseController with a ViewBag
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
ViewBag.HeadStart = whatever comes from the database;
ViewBag.HeadEnd = whatever comes from the database;
ViewBag.BodyStart = whatever comes from the database;
ViewBag.BodyEnd = whatever comes from the database;
}
}
Then in every controller you'll inherit from this base controller
public class HomeController : BaseController
{
// some methods here
}
And finally in the view
<head>
#if (ViewBag.HeadStart != null)
{
#foreach (var script in ViewBag.HeadStart)
{
#Html.Raw(#script.Code);
}
}
#RenderSection("headScripts", required: false)
#* do the same for end *#
</head>
<body>
#* same thing here as well *#
</body>
I'm getting an external page HTML code from my Backend as a string
and displaying it in a Webview in a Xamarin forms app
Now I would like to style it
I was wondering what is the most efficient way to do that?
and is it possible to style it in the same way a Xamarin Page would get styled with XAML and shared resources?
so far I tried referencing a CSS file in the shared resources, which I found out doesn't work...
htmlData = "<link rel=\"stylesheet\" type=\"text/css\"href=\"Assets\"Styles\"style.css\" />" + htmlData;
htmlSource.Html = htmlData;
myWebView.Source = htmlSource;
Update
I ended up using a custom renderer for the Webview
which worked for Android but not for IOS
here is my IOS implementation of the renderer
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace XXX.iOS.Renderers
{
public class CustomWebViewRenderer : WkWebViewRenderer
{
WKUserContentController userController;
public CustomWebViewRenderer() : this(new WKWebViewConfiguration())
{
}
public CustomWebViewRenderer(WKWebViewConfiguration config) : base(config)
{
userController = config.UserContentController;
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
var customWebView = e.NewElement as CustomWebView;
if (e.NewElement != null)
{
string htmldata = customWebView.HTMLData;
htmldata = "<link rel=\"stylesheet\" type=\"text/css\" href=\"StyleSheet.css\" />" + htmldata;
WkWebViewRenderer wkWebViewRenderer = new WkWebViewRenderer();
NSData data = NSData.FromString(htmldata);
wkWebViewRenderer.LoadData(data,"text/html", "UTF-8",new NSUrl(""));
}
}
}
}
Note: I don't have any idea what is happening here with the IOS code, cause I have never coded in the native language
I don't know whether this is feasible for you, but you could inject the actual CSS in the HTML string and then assign the HtmlSource
var css = ReadStringFromAsset("style.css");
htmlData = InjectCssInHtml(htmlData, css);
htmlSource.Html = htmlData;
myWebView.Source = htmlSource;
Depending on how much control you have over the HTML you receive, you have several option on how to realize InjectCssInHtml
Pseudo-Markup comment
If changing the HTML is feasible, you could add an HTML comment as a pdeudo markup. This will make the code simple, but each HTML must be edited accordingly
<html>
<head>
<style>
<!-- CSS -->
</style>
...
</html>
your InjectCssInHtml then becomes
string InjectCssInHtml(string html, string css)
{
return html.Replace("<!-- CSS -->", css);
}
Without editing the HTML
If editing the HTML is not feasible, the InjectCssInHtml becomes a tad more complicated. The following is a first guess, but I think you get the idea
string InjectCssInHtml(string html, string css)
{
string codeToInject;
int indexToInject = 0;
if(ContainsStyleTag(html))
{
indexToInject = IndexOfStyleTagContent(html);
codeToInject = css;
}
else if(ContainsHeadTag(html))
{
indexToInject = IndexOfHeadTagContents(html);
codeToInject = $"<style>{css}</style>";
}
else
{
indexToInject = IndexOfHtmlTagContents(html);
codeToInject = $"<head><style>{css}</style></head>";
}
return html.Insert(indexToInject, codeToInject);
}
Surely this does not cover each possible case, but I think you get the idea. The ìf-else` could be replaced by an abstract factory generational pattern combined with the strategy behavioral pattern.
string InjectCssInHtml(string html, string css)
{
ICssInjector injector = injectorFactory.CreateInjector(html);
return injector.InjectCss(html, css);
}
I create footer module with Inner-Content.
But since this module is footer module and is displayed on all pages I have problem with automatic "Quick-Insert" hide for page modules.
Is it posible to configure or there is some workaround that I can have "Quick-Insert" and "Inner-Content-Block" on the same page?
Or is it possible to disable "Inner-Content-Block" for my module and add "sub modules" another way?
2sxc V8.04.08 / dnn V8.00.03
As workarount I solve this that way:
1.
create App.Setting bool value (HideInnerContentAdd)
2.
create web api for toggle this value
using DotNetNuke.Security;
using DotNetNuke.Web.Api;
using System.Web.Http;
using ToSic.SexyContent.WebApi;
using System;
using System.Linq;
using System.Collections.Generic;
using ToSic.SexyContent;
using System.Dynamic;
public class nnFootBoxController : SxcApiController
{
// ########################################################################################
[HttpGet]
[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]
[ValidateAntiForgeryToken]
public dynamic ToogleInnerContentMenu()
{
var tObj = AsDynamic(App.Settings);
if (tObj==null) return false;
var state = false;
if (tObj.HideInnerContentAdd!=null) state = (bool)(tObj.HideInnerContentAdd);
state = !state;
var newValues = new Dictionary<string, object>();
newValues.Add("HideInnerContentAdd", state);
App.Data.Update(tObj.EntityId, newValues);
return state;
}
// ########################################################################################
}
3.
add code to footer of module you want to be shown on all pages for changing state.
#if(Permissions.UserMayEditContent){
<link rel="stylesheet" type="text/css" href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css" data-enableoptimizations="true" />
<script type="text/javascript" src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js" data-enableoptimizations="true"></script>
<script type="text/javascript" src="/DesktopModules/ToSIC_SexyContent/Js/2sxc.api.min.js" data-enableoptimizations="true"></script>
<script type="text/javascript" src="#App.Path/js/toggle-innercontentshow.js" data-enableoptimizations="true"></script>
<div>
<input class="nn-toggle-innercontentshow" type="checkbox" #innerContentMenuChecked() data-toggle="toggle" data-on="On" data-off="Off" onchange="nnFooterBox_cbToggle(this,#Dnn.Module.ModuleID)">
</div>
}
#functions{
public dynamic lib { get { return CreateInstance("../_Shared.cshtml"); } }
public string innerContentMenuChecked(){
return isInnerContentMenuVisible() ? "checked" : "";
}
public string innerContentMenuClass(){
return isInnerContentMenuVisible() ? "sc-content-block-list" : "";
}
public bool isInnerContentMenuVisible(){
var tState = ((DynamicEntity)(App.Settings)).HideInnerContentAdd;
if (tState=="True") return false;
return true;
}
}
4.
Change code for render inner content...
<!-- start modules -->
<div class="#innerContentMenuClass()" #Edit.ContextAttributes(Content, field: "Modules")>
#foreach(var cb in Content.Modules) {
#cb.Render();
}
</div>
<!-- end modules -->
With #innerContentMenuClass() enable or disable Quick Add For Inner Content Blocks...
5.
I know that this Is not nice code but work for me...
If somebody have nicer code please help me back...
I'm adding some content to a given web page from code behind. When I want to add a break after some text, I try to do that this way:
pDoc.Controls.Add(New Label With {.Text = "whatever"})
pDoc.Controls.Add(New HtmlGenericControl("br"))
,where pDoc is the Panel in which I'm adding the content. But it adds two br tags into the final HTML.
I've avoid this behaviour this way:
pDoc.Controls.Add(New Label With {.Text = "whatever" & "<br />"})
Anyway, I'm so curious and I want to know why
pDoc.Controls.Add(New HtmlGenericControl("br"))
is acting that way. I also think my approach is not too fancy.
Regards,
Actually you can use;
pDoc.Controls.Add(new LiteralControl("<br/>"));
Whereas new HtmlGenericControl("br") adds two <br>, this will only add <br/> tag to your HTML so that you just have 1 space line.
In this picture I added those breaks with that code block.
Also similar question here: Server control behaving oddly
After some testing it looks like the reason is that HtmlGenericControl doesn't support self closing. On server side the HtmlGenericControl("br") is treated as:
<br runat="server"></br>
There is no </br> tag in HTML, so the browser shows it as there are two <br /> tags. Nice way out of this is to create HtmlGenericSelfCloseControl like this (sorry for C# code but you should have no issue with rewritting this in VB.NET):
public class HtmlGenericSelfCloseControl : HtmlGenericControl
{
public HtmlGenericSelfCloseControl()
: base()
{
}
public HtmlGenericSelfCloseControl(string tag)
: base(tag)
{
}
protected override void Render(HtmlTextWriter writer)
{
writer.Write(HtmlTextWriter.TagLeftChar + this.TagName);
Attributes.Render(writer);
writer.Write(HtmlTextWriter.SelfClosingTagEnd);
}
public override ControlCollection Controls
{
get { throw new Exception("Self closing tag can't have child controls"); }
}
public override string InnerHtml
{
get { return String.Empty; }
set { throw new Exception("Self closing tag can't have inner content"); }
}
public override string InnerText
{
get { return String.Empty; }
set { throw new Exception("Self closing tag can't have inner text"); }
}
}
And use it instead:
pDoc.Controls.Add(New Label With {.Text = "whatever"})
pDoc.Controls.Add(New HtmlGenericSelfCloseControl("br"))
As a simpler alternative (if you have reference to the Page) you can try using Page.ParseControl:
pDoc.Controls.Add(New Label With {.Text = "whatever"})
pDoc.Controls.Add(Page.ParseControl("br"))
I guess what I want to do is "chain" my data down so that it ends up looking the same.
All my html must be wrapped in some form of
<fieldset class="" data-role="">
So what I have is a helper that prints the various forms. One would be a label:
<fieldset data-role="#role">
<label>#Html.Raw(label)</label>
</fieldset>
Now when I have multiple types of labels, and one includes being a code block. When it is a
simple piece of text, like "First Name" I do:
#FieldSet.Label("First Name")
But when I have a code block such as:
<b>some text</b>
<p>some other text (some time frame - some time frame)
It becomes complicated to use this:
#FieldSet.Label("<b>" + Model.Text1 + "</b><p>" + Model.Text2 +
" (" + Model.Time1 + " - " + Model.Time2 +")</p>")
What I want it a solution that looks something like this:
#FieldSet.Label(#<text>
<b>#Model1.Text1</b>
<p>#Model.Text2 (#Model.Time1 - #Model.Time2)</p>
</text>)
I read somewhere this was possible, but I cannot find the article. I could be completely misled, but I really don't want to have a single piece of HTML in the code behind and I want to utilize the razor syntax, not string concatenation.
Check this articles from Phil Haack
http://haacked.com/archive/2011/02/27/templated-razor-delegates.aspx
http://haacked.com/archive/2011/04/14/a-better-razor-foreach-loop.aspx
You could:
Write as an extension method to a strongly-typed HtmlHelper:
public static class RazorExtensions
{
public static HelperResult Label<T>(this HtmlHelper<T> helper, Func<T, HelperResult> template) {
return new HelperResult(writer => {
writer.Write("<label>");
template(helper.ViewData.Model).WriteTo(writer);
writer.Write("</label>");
});
}
}
So you could write
#Html.Label(#<text><span>#Model.Item1<span><strong>#Model.Item2</strong></text>)
Pass Model as a parameter to your helper method
public static class FieldSet
{
public static HelperResult Label<T>(this T model, Func<T, HelperResult> template) {
return new HelperResult(writer => {
writer.Write("<label>");
template(model).WriteTo(writer);
writer.Write("</label>");
});
}
}
Usage:
#FieldSet.Label(Model, #<div><span>#Model.UserName</span><strong>#Model.FullName</strong><p>#Model.Description</p></div>)
You could look at how the #Html.BeginForm is implemented.
Create a class that implements IDisposable, and that writes to the Response stream directly:
Your code could look like this (entered by head, not tested):
class FieldSet : IDisposable {
public FieldSet(string label) {
// TODO: Encode label on line below
HttpContext.Current.Response.Write(string.Format("<fieldset><label =\"{0}\"", label));
}
public void Dispose() {
HttpContext.Current.Response.Write("</fieldset>");
}
}
static class FieldSetExtionsions {
public static FieldSet FieldSet(this HtmlHelper html, string label) {
return new FieldSet(label);
}
}
The usage will be:
#using (Html.FieldSet("your label")) {
<div>
Your razor code goes here
</div>
}