I'm no guru in Razor syntax, but trying to build a generic library using a fluent-style à là Telerik's GUI components.
I have the following pieces (approximately):
public static MyBox Box(this HtmlHelper helper)
{
return new MyBox(helper.ViewContext);
}
and:
/// <summary>
/// http://geekswithblogs.net/shaunxu/archive/2010/04/10/lt-gt-htmlencode-ihtmlstring-and-mvchtmlstring.aspx
/// </summary>
public class MyBox : IHtmlString
{
private readonly ViewContext _viewContext;
private string _content;
private string _title;
public MyBox(ViewContext viewViewContext)
{
_viewContext = viewViewContext;
}
/// <summary>
/// See: http://haacked.com/archive/2011/02/27/templated-razor-delegates.aspx
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public MyBox Content(Func<object, object> value)
{
_content = value.DynamicInvoke(_viewContext).ToString();
return this;
}
/// <summary>
/// See: http://haacked.com/archive/2011/02/27/templated-razor-delegates.aspx
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
public MyBox Content(params Func<object, object>[] values)
{
foreach (var value in values)
{
_content += value.DynamicInvoke(_viewContext).ToString();
}
return this;
}
public MyBox Content(MvcHtmlString content)
{
_content = content.ToString();
return this;
}
public MyBox Title(string title)
{
_title = title;
return this;
}
public string ToHtmlString()
{
using (var stringWriter = new StringWriter())
{
WriteHtml((TextWriter)stringWriter);
return stringWriter.ToString();
}
}
public void Render()
{
using (var writer = new HtmlTextWriter(_viewContext.Writer))
WriteHtml(writer);
}
protected virtual void WriteHtml(TextWriter writer)
{
writer.WriteLine("<!-- START BOX -->");
writer.WriteLine("<h1>" + _title + "</h1>));
writer.WriteLine(_content);
writer.WriteLine("<!-- END BOX -->");
}
}
I also have a set of Html extension methods that return MvcHtmlString's. One example is (simplified):
public static class GuiElementExtensions
{
private const string FieldContainerHeadingTemplate = @"
<tr><th style=""text-align:left"" colspan=""2"">{0}</th></tr>
";
public static MvcHtmlString GuiFieldContainerHeading(this HtmlHelper helper, string text)
{
return new MvcHtmlString(String.Format(FieldContainerHeadingTemplate, text));
}
}
Then, in my .cshtml file, I do the following:
@using (Html.BeginForm())
{
@(Html.Gui()
.Box()
.Title("Hello World!")
.Content(
@<h1>Hello World! This is the cool Gui.Box</h1>
)
)
}
Which calls public MyBox Content(Func<object, object> value)
, and works.
Similarly, when I try the following:
@using (Html.BeginForm())
{
@(Html.Gui()
.Box()
.Title("Hello World!")
.Content(
Html.GuiFieldContainerHeading("SubHeading 1")
)
)
}
It happily calls public MyBox Content(MvcHtmlString content)
and works as expected.
But, however, when I try to do the following, I can't wrap my head around how the Razor compiler engine works. How do I get it to return the sum of
@<h1>Hello World! This is Gui().Box()</h1>
(which is a Func)Html.GuiFieldContainerHeading("SubHeading 1")
(which is an MvcHtmlString)as either one object (be it a Func, MvcHtmlString, whatever, or a list of objects? I would like to write generic Razor syntax inside the parameter list to the Content function in my MyBox class, like this:
@using (Html.BeginForm())
{
@(Html.Gui()
.Box()
.Title("Hello World!")
.Content(
@<h1>Hello World! This is Gui().Box()</h1>
Html.GuiFieldContainerHeading("SubHeading 1")
Html.TextBoxFor(model => model.Name)
@<h2>Hello there!</h2>
)
)
}
Am I on the right track whatsoever, or is there a much simpler way of doing what I want? I want to gather all the "common gui elements" in our system in a common DLL, so not every developer in my organization needs to reinvent the wheel on each project.
Any help appreciated.
OK, next problem:
I have generalized the Box into a Container, and created two subclasses, Box and HighlightArea. However, using the following code, the Razor compiler kicks me with the message
Inline markup blocks (@<p>Content</p>) cannot be nested. Only one level of inline markup is allowed.
The code not working, is:
@(Html.Gui()
.Box()
.Title("BoxTitle")
.Content(@<text>
<h1>Hello World! This is the box content</h1>
@Html.GuiFieldContainerHeading("This is the heading")
@(Html.Gui().HighlightArea()
.Content(
@Html.ValidationSummary()
@<h1>Jalla</h1>
)
)
</text>
)
Do we have a workaround for this? Or is my approach not feasible?
You could use the <text>
tag to combine everything into one parameter.
@using (Html.BeginForm())
{
@(Html.Gui()
.Box()
.Title("Hello World!")
.Content(
@<text>
<h1>Hello World! This is Gui.Box</h1>
@Html.GuiFieldContainerHeading("SubHeading 1")
@Html.TextBoxFor(model => model.Name)
<h2>Hello there!</h2>
</text>
)
)
}
I guess your example isn't really working. If I'm not mistaken you could get it working like this:
@<h1>Hello World! This is Gui.Box</h1>
+ Html.GuiFieldContainerHeading("SubHeading 1")
+ Html.TextBoxFor(model => model.Name)
+ @<h2>Hello there!</h2>
But the <text>
tag seems easier.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With