control template in asp.net mvc - asp.net-mvc

Previous to MVC, when webforms was the only thing we had, I used to define a container for my controls (A Box you may call) and used this web control (with title, body and a couple of other properties) in other controls.
So if I wanted to change the look of all my visual controls, I just had to make one change in my Box control.
Here's a simplified snippet of what I used to do:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Box.ascx.cs" Inherits="WebApp.Controls.Box" %>
<span class="boxtitle">
<asp:Literal ID="ltrTitle" runat="server"></asp:Literal>
</span>
<div class="boxContent" id="dvBox">
<asp:PlaceHolder runat="server" ID="BoxBodyContainer"/>
</div>
And in code-behind:
public Control BoxBody { get; set; }
public string Title
{
get { return this.ltrTitle.Text; }
set { this.ltrTitle.Text = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
this.BoxBodyContainer.Controls.Add(this.BoxBody);
}
So I could use this along with other controls in my page as follows:
<MyControls:Box ID="Box1" Title="Foo" runat="server">
<boxbody>
<MyControls:CustomControl ID="Bar" runat="server" >
</MyControls:CustomControl>
</boxbody>
</MyControls:Box>
In order to have something alike in MVC 3, I think I should define a Box view and wherever I need the box, use Html.Partial or Html.Action and pass all my data (title, boxbody, etc) to this view and use #Html.Raw in Box view.
But I was wondering if there's any better, more standard way to achieve this.
What's the correct way of achieving this in MVC 3 (Razor)?

You can create an Html Helper extension method to do this. The best tutorial I could find was for MVC2, but it gives you the basics.
What the tutorial doesn't cover is that there are classes in the System.Web.MVC namespace that can help you create html in code.
Note: The following code hasn't been tested.
using System;
using System.Web.Mvc;
public static class HtmlExtensions
{
public static MvcHtmlString Box(this HtmlHelper helper, string title, MvcHtmlString body)
{
TagBuilder span = new TagBuilder("span");
span.AddCssClass("boxtitle");
span.SetInnerText(title.ToString());
TagBuilder div = new TabBuilder("div");
div.AddCssClass("boxContent");
div.InnerHtml = body;
return MvcHtmlString.Create(span.ToString() + div.ToString());
}
}
You can call this method from the razor view like so:
#Html.Box("foo", Html.Partial("bar"))

Related

Converting webform usercontrol to MVC 4 control

I am trying to convert a webform usercontrol to MVC based usercontrol.
MessageControl.ascx
public abstract class Feedback : System.Web.UI.UserControl
{
public string Message {get;set;}
}
public void ShowError()
{
lblMessage.InnerHtml = Message;
}
So In aspx pages I can call the public method ShowError and pass the error which will be displayed in the usercontrol ascx file.
Aspx pages
protected void Page_Load(object sender, System.EventArgs e)
{
if(isError = true)
{
MessageControl1.Message = "Error Occured";
}
}
How can I achieve the same in MVC 4.0 ?
Any help would be appreciated.
The correct way would be to use the model state for strongly typed models. Another more manual way which I regularly use is to put error messages into Viewbag and then on the view check if the entry in the Viewbag exists and if it does display the error. for example (in asp.net mvc):
<div id="notification_error" class="invalid" <%if (String.IsNullOrEmpty(""+TempData[ "ErrorMsg" ])){ %>style="display: none;"
<%} %>>
<%= TempData["ErrorMsg"] %>
</div>

Creating html helpers without encoding

I'm trying to create an html helper to render a button. As an example this needs to contain -
<button onClick="window.location='/Users/Edit/admin'">
I have tried to do this using TagBuilder but am having issues because MergeAttribute is encoding the html.
e.g.
buttonBuilder.MergeAttribute("onClick", "window.location='" + url.Action(action, controller, routeValues));
gives me -
<button onClick="window.location='/Users/Edit/admin">
Is there a way I can do this so it's not encoded? Or should I be using another method other than TagBuilder?
--EDITED
I almost forget, use the HtmlDecode:
public static class ButtonHelper
{
public static IHtmlString Button(this HtmlHelper html)
{
TagBuilder button = new TagBuilder("button");
button.MergeAttribute("onClick", "window.location='/Users/Edit/admin'");
return new HtmlString(System.Web.HttpUtility.HtmlDecode(button.ToString()));
}
}
Or look it: http://forums.asp.net/t/1377957.aspx/1

Custom render with unobtrusive validation, dont work, why?

Im trying to do a little render framework, since I need some more control over the render process. Fx. if a property need to be rendered in a tab.
So I set out to, render a TextBox, but it does not validate with server side or client side validation (the MVC unobtrusive validation)
I have taken my framework out, and recreated a little eksampel
public class Foo
{
public virtual int Id { get; set; }
[System.ComponentModel.DataAnnotations.Required]
public virtual string Name { get; set; }
public virtual DateTime StartTime { get; set; }
}
My extension method:
public static MvcHtmlString DummyForm(this HtmlHelper html)
{
StringBuilder sb = new StringBuilder();
Type oftype = typeof(Foo);
string[] propertyNameToRender = oftype.GetProperties().Select(o => o.Name).ToArray();
foreach (string s in propertyNameToRender)
{
MvcHtmlString htmlstring = System.Web.Mvc.Html.InputExtensions.TextBox(html, s);
sb.AppendLine(htmlstring.ToHtmlString());
}
return MvcHtmlString.Create(sb.ToString());
}
And on the Edit.cshtml
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true);
#Html.DummyForm()
}
If I look at the rendered html output, its the same (without the validation attri)
Can anyone tell me, why the validation attri, is not rendered.
Im using the mvc's own render controls, HtmlHelper is passed from the view, with all ModelMetadata and ModelState.
Unobtrusive validation data-val-* attributes are rendered when FormContext is initialized. Html.BeginForm does that, so
#using (Html.BeginForm())
{
#Html.DummyForm()
}
Should render inputs with validation attributes.
There is one thing that seems odd is that you are calling System.Web.Mvc.Html.InputExtensions.TextBox method yourself. This method is internally called by Html.TextBox and other strongly typed extensions. plz try changing
MvcHtmlString htmlstring = System.Web.Mvc.Html.InputExtensions.TextBox(html, s);
to
MvcHtmlString htmlstring = html.TextBox(s);
I have try to create a new ASP.net MVC site, and added the code from my RenderProject, and it works fine. The conclusion is my asp.net MVC project messed up. I dont why. :S

does mvc.net validation support the concept of ValidationGroup

Coming from the asp.net background, I really appreciated the concept of 'validationGroup' when adding validation to a page. I've been searching for a corresponding concept within mvc.net and haven't had much luck.
Is this concept available in mvc.net? If not, what alternatives do I have?
Unfortunately no, it doesn't come with anything like that.
I blogged about a workaround a wee while back.
ASP.NET MVC - Validation Summary with 2 Forms & 1 View
The jist of the blog post:
namespace System.Web.Mvc
{
public static class HtmlExtensions
{
public static string ActionValidationSummary(this HtmlHelper html, string action)
{
string currentAction = html.ViewContext.RouteData.Values["action"].ToString();
if (currentAction.ToLower() == action.ToLower())
return html.ValidationSummary();
return string.Empty;
}
}
}
And
<h2>Register</h2>
<%= Html.ActionValidationSummary("Register") %>
<form method="post" id="register-form" action="<%= Html.AttributeEncode(Url.Action("Register")) %>">
... blah ...
</form>
<h2>User Login</h2>
<%= Html.ActionValidationSummary("LogIn") %>
<form method="post" id="login-form" action="<%= Html.AttributeEncode(Url.Action("LogIn")) %>">
... blah ...
</form>
HTHs,
Charles
Expanding on Charlino's answer, and including HtmlAttributes and other ValidationSummary properties:
public static MvcHtmlString ActionValidationSummary(this HtmlHelper html, string action, bool excludePropertyErrors, string message, object htmlAttributes = null)
{
var currentAction = html.ViewContext.RouteData.Values["action"].ToString();
if (currentAction.ToLower() == action.ToLower())
{
return html.ValidationSummary(excludePropertyErrors, message, htmlAttributes);
}
return new MvcHtmlString(string.Empty);
}
Charles's method was the only approach I could find that actually worked for my purposes!
(I.e. two forms on one MVC page -> without doing forms inside partials and ajax loads for the partials. This was no good for me, as I wanted to return differing result sets to be rendered outside the form div, depending on which form was submitted)
I would advise a slight modification to the Html Extension though, because you still want a validation summary to be rendered for the non-matched validation summary so that client side validation works:
namespace System.Web.Mvc
{
public static class HtmlExtensions
{
public static MvcHtmlString ActionValidationSummary(this HtmlHelper html, string action)
{
string currentAction = html.ViewContext.RouteData.Values["action"].ToString();
if (currentAction.ToLower() == action.ToLower())
return html.ValidationSummary();
return new MvcHtmlString("<div class=\"validation-summary-valid\" data-valmsg-summary=\"true\"><ul><li style=\"display:none\"></li></ul></div>");
}
}
}

What is the ASP.NET MVC equivalent of displaying a Label conditionally?

I'm currently porting an ASP.NET WebForms application to ASP.NET MVC.
In one of the pages there is an ASP.NET Label control which is displayed conditionally based on a variable in the codebehind. So, something to the effect of
<asp:Label runat="server" Visible="<%# ShowLabel%>">
...
</asp:Label>
Where ShowLabel is a Boolean value in the codebehind. The contents of the label are generated at runtime and will be different pretty much every time.
There's better ways to do this even in ASP.NET, but what would be the best way to do this in ASP.NET MVC? How are you even supposed to render dynamic text in ASP.NET MVC in a way similar to how the ASP.NET Label object worked?
I believe in the Thunderdome principle of having one ViewModel class for each View (unless it is a very simple view).
So I would have a ViewModel class like the following:
public class IndexViewModel
{
public bool labelIsVisible { get; set; }
public String labelText { get; set; }
public IndexViewModel(bool labelIsVisible, String labelText)
{
this.labelIsVisible = labelIsVisible;
this.labelText = labelText;
}
}
In your controller, do something like,
public ActionResult Index()
{
// Set label to be visible in the ViewModel instance
IndexViewModel viewData = new IndexViewData(true, "Simucal rocks!");
return View(viewData);
}
Where Index is a strongly typed view of type IndexViewModel.
Then, in your view simply do something like:
<% if (Model.labelIsVisible) { %>
<%= Model.labelText %>
<% } %>
The main idea in MVC is NOT to pass the strings you want to display; you should pass the relevant objects to your View, and the View, in turn, would decide wether to display that label or not (and this is using a simple if, like in Simucal's sample).
So, instead of doing
if (Model.labelIsVisible) {
One would do
if (Model.Comments == 0) {
For example, if the label would be to show a prompt for a user to comment on an article.
Take your element in and set on hide() function like that:
<div id="label">
#Html.Label("myLabel", "text")
</div>
$("#label").hide();`

Resources