How can I use custom controls with ASPNET.MVC Razor?
I want to use a custom control on a Razor view. for instance:
<mycontrols:something>#Model.MyVar</mycontrols:something>
or
<mycontrols:something myattribute="#Model.MyVar" />
Please note that my goal is to use only few controls derived from MvcControl, only for trivial repetive ui stuffs.
I tried to find out a syntax similar to #Register to write on the top of the view, but without any success.
Then I went to the web.config, adding
<pages>
<controls>
<add tagPrefix="mycontrols" namespace="mynamespace" assembly="myassembly"/>
</controls>
</pages>
but it looks like custom controls are ignored in rendering.
Someone could help?
...Might be it is a little bit old fashion, but sometimes also custom control could be useful to make your code cleaner!
The Razor syntax does not support the notion of Controls at all. If you want to use controls you will have to use the ASPX (WebForms) syntax.
However, the recomended MVC pattern is to use html helper functions or partial views. In Razor you can also use the #helper syntax for quick helper functions.
In ASP.NET MVC custom server controls should be avoided. Most of them rely on ViewState and PostBack which are notions that no longer exist in MVC. You should prefer using templates, HTML helpers to implement some reusable functionality. Another problem with controls is most of them encapsulate some business logic which fetches data from somewhere and renders it which is an anti-MVC pattern. In MVC it is the controller responsibility to manipulate the model and fetch data and pass a view model to the view which simply should display it.
MVC uses partial views rather than custom controls, and they can be used in two ways that cover pretty much everything a custom control can do
RenderPartial which renders data already retrieved by the page controller
RenderAction which is similar but has its own controller action so can get data independently
The only scenario I can think of where it would be worth putting a custom control on an mvc view is if you are working on a partially migrated webforms project, and I doubt that would work with anything other than the WebFormsViewEngine.
You can do this, though I don't recommend it, though I'm not here to judge. I might add that I don't expect postback and view state to continue working either but you can at least render all of the html.
The only way to do this is a bit of a hack, because razor doesn't support webforms view engine controls. However, it does support partial views made in the webforms View engine. So a hacky solution is to include a partial view with your control in it as such:
For example, say you want to use the office web ui ribbon in your mvc3 project, you could do so by including
<body>
<div>
#Html.Partial("_RibbonPartial")
</div>
</body>
in your view. Where _Ribbon is of type .aspx
then in your partial view simply use your control and set runat="server" and put it inside of a form with runat="server"
//_Ribbon.aspx
<form id="form1" runat="server">
<XyzControls:Manager ID="Manager1" runat="server" UITheme="Silver" />
<XyzControls:OfficeRibbon ID="OfficeRibbon1" runat="server" ApplicationMenuColor="#267c29"
ApplicationMenuText="Item" ApplicationMenuType="Backstage">
//... rest of control code
</form>
Then you need to use ajax to implement events instead of using postback.
Then to cleanup, get rid of the generated code from webforms view engine for post back that you don't need.. You can try keeping it, I haven't so I'm not sure what will happen. I know there are ways to have a fake viewstate as well if you really want to get into messy hacky stuff, but to remove the extra code from webforms you can use the following jquery:
$(function ()
{
// we don't need any of the webforms stuff
$("#__EVENTTARGET","#aspnetForm").parents("div:first").remove();
$("#__EVENTVALIDATION","#aspnetForm").parents("div:first").remove();
});
I had the same demand. Wanted to use custom webcontrol from Razor/MVC page. One should not do that with controls, that is handling postback. You don't have the eventcycle to support that, but if your only demand is to use a 'rendering control', you could instantiate it in razor, and control where the rendering takes place:
#{
var myControl = new mycontrols.something();
myControl.myattribute = Model.MyVar;
mycontrol.RenderControl(new HtmlTextWriter(this.Output));
}
Related
I ask a relevant question here and as I find there is no way to use custom control in Razor views, so I get to add new ASPX partial view to use custom control, my custom control is a dll that I added to References then define Partial view as the following:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>" %>
<%# Register Assembly="JQControls" Namespace="JQControls" TagPrefix="PersianDatepicker" %>
<PersianDatepicker:JQLoader ID="jqdb" runat="server" />
<PersianDatepicker:JQDatePicker ID="jqdp1" runat="server" Regional="fa" />
I write the exact code in ASPX Web form and worked correctly but there is an exception in MVC:
Error executing child request for handler
'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerWrapper'.
Exception of type 'System.Web.HttpUnhandledException' was thrown.
Object reference not set to an instance of an object.
So does any one have any idea about it?
Another question is how can I define a Html Helper for this user control (With dll and I have not access to code) ?
make a html iframe into view, loading a aspx page!
the "View" in MVC template should be standard HTML form.
you may use "Helper" to generate complex/re-useable HTML output but using any standard HTML+Javascript in UI is the way "MVC" works.
MVC allow parallel coding and HTML development. any developer who knows HTML+JS can create "View" without messing up your code.
this jquery plugin http://jqueryui.com/demos/datepicker/ can create custom DatePicker on client browser.
asp:PlaceHolders have a visible property, and this controls whether their content is rendered on the page.
I have declared a PlaceHolder in an MVC2 Master Page and set it's visibility to false.
Please can you tell me how I can control the visibility of a PlaceHolder from within an MVC2 view template that inherits from an MVC2 master page?
This seems like a simple task, but I am struggling to see how it can be achieved. I think I should be able to get access to the PlaceHolder from within the descending view template (as with web forms code-behind) and just set it's visibility there but the way to do this is escaping me...
Don't do this. Placeholders are legacy from classic WebForms. Manipulating server side controls in an ASP.NET MVC application is very bad and you should never do it. So simply forget about setting properties on user controls. Fortunately in Razor placeholders have been completely removed and replaced by sections. So don't write code that you won't be able to migrate later.
One way to show/hide sections of your code in an ASP.NET MVC application is to use an if statement in your views. For example:
<% if (Model.ShouldShowSection) { %>
<div>Some super section</div>
<% } %>
In this example we are testing a boolean value on the view model which the controller action that rendered this view would set.
I'm porting an application from WebForms to MVC.
I have a WebForms UserControl that is used throughout the site and which contains presentational and business logic, and in particular some 'initizliation' logic (in the Page_Load)
My understanding of MVC UerControls is that they have no dedicated controller and thus contain no logic, and the logic is added to the controller of the viewpage to which the UserControl is added.
Now, I don;t want to have to write the initialization logic in my ViewPage, as this UserControl appears on several pages, thus duplication of logic.
I don't think I can user a MasterPage, as the UserControl can be rendered either vertically to the left of the page or hozontally at the top of the page depending on what page it is. This would require 2 MasterPage's, and again duplication of logic.
Do I have any other options?
This is a good case to use the RenderAction html helper. Much better, grab the Microsoft MVC futures and use the RenderAction method. Basically it lets you call a controller action within a view, which is alot more like how UserControls work than RenderPartial.
Bleh, I guess I should do it properly and pass in a object via my controller's viewdata rather than hacky-slash it.
I have existing ASP.NET MVC View pages and View user controls which I currently use in normal straightforward ASP.NET MVC fashion, sometimes I use RenderPartialView or RenderAction, etc.
By themselves they include tag. I would like to dynamically load either Views or ViewUserControl based on the selection in a dropdown list.
I'm having trouble deciding should I remove from Views and controls and put it just into the one View that will do dynamic rendering or to leave it there and leave outside of the .
What do you think and how would you go about it?
I would probably try to load the contents of a div after doing an AJAX call to get the contents. See the AJAX get call in the jQuery docs.
Or are the possibilities of what control to load so small you could just hide/show div's that are already in the page?
You can use JQuery to get the HTML from your Partial views and substitute it in the div. It could be something like this:
$.get('/Controller/Action',function(data){
$('div').innerHtml(data);
});
I did it this way and it works. /Controller/Action can be a partial view which returns HTML.
I make heavy use of View Components in some of the larger applications I've built in Monorail - What is the equivalent approach in ASP.Net MVC for a view component, that can support sections etc.?
Actually you have several options to create the equivalent of a ViewComponent in ASP.NET MVC, depending in the complexity of your component. I use these two approaches which are the more mvc-ish of the options I am aware of.
1:
The simplest thing is to create a ViewUserControl and display it using Html.RenderPartial with the helper. The ViewUserControl is a simple piece of markup with no backing controller (I think you can put a codebehind file if you want).
Optionally, you can pass a model object or the entire ViewData dictionary to the view when calling RenderPartial, like this:
<% Html.RenderPartial("TopBar", model); %>
"TopBar" is an ascx page. This works anywhere, in master pages and in normal views.
2:
If you want your component to have more complicated logic or to access datasources, IoC, etc, then you can use Html.RenderAction which is an extension method found in the Microsoft.Web.Mvc assembly. I am using this out of the mvccontrib distribution. It works like this, you need to create a normal controller with all the logic you need, then create some views and all of these things become your component, for example:
public class AboutComponentController : Controller {
public IRepository Repository{ get; set; }
public ActionResult Detail() {
var lastEvent = Repository.FindAll<Auditoria>().FirstOrDefault();
return View(lastEvent);
}
}
Notice how I have a reference to an IRepository which is going to be injected with IoC (Windsor in my case) and I can do anything a normal controller would do.
Now, in any page (master or normal) where you want to use your component, import Microsoft.Web.Mvc and call Html.RenderAction with the appropriate parameters. This will create a mini mvc pipeline that creates the controller, resolves the view, etc., just like a Monorail ViewComponent. I prefer to use the lambda based variation of the method, like this:
<% Html.RenderAction<AboutComponentController>(x => x.Detail("a message"));%>
Unfortunately, the only way to pass parameters is to use the method call itself, which in turn must be unique in the controller. Still needs some work to resemble a ViewComponent.
I don't use masterpages or layouts in the views of my components since they are composition elements themselves.
Remember that when using the Webforms view engine, you can have strongly typed views if you like to have intellisense when using the Model variable in code blocks.
The beauty of this is that you can mix view engines with these approaches, I usually create the components in nvelocity and display them in aspx pages, etc.
I now there can be issues with caching of the partial views but I haven't run into any so far. I am sure there are other options (like subcontrollers in mvccontrib) but this is usually enough for simple cases. Of course you can use normal ASP.net components in your aspx view pages but that would be cheating right? hehe. I hope it helps.
Phil Haack blogged about creating areas to group controllers into sub-folders/sections similar to MonoRails.