For rendering my menu in MVC 3 Razor I have in the Home controller a Menu action: public ActionResult Menu() {...}
This action gets the menu items and render them using a view. In the _Layout I use: #Html.Action("Menu", "Home") for rendering the menu. This works fine.
My problem is that I want to select the current item. For this each action that render an item that is in the menu will add to the ViewBag the selected menu item. The problem is that the ViewBag is empty in the Menu action.
Is this the correct approach? I want to render a menu using a controller + view not only a view. I want this in order to avoid having logic code in the view code and to be able to test it.
Do you know a better approach?
How can I pass data from _Layout.cshtml to an action that I render using #html.Action?
You could pass it as parameter:
#Html.Action("Menu", "Home", new { sleectedItem = (string)ViewBag.SomeItem })
and then in the child controller action use this:
public ActionResult Menu(string selectedItem)
{
...
}
or if all you need is to fetch the current controller and action you could simply fetch this information from the RouteData and get rid of any ViewBag:
public ActionResult Menu()
{
var rd = ControllerContext.ParentActionViewContext.RouteData;
var action = rd.GetRequiredString("action");
var controller = rd.GetRequiredString("controller");
// Now that you know the action and the controller build up your view model
// and pass to the view. It will then know which menu item to preselect
...
}
Try looking at the RouteData from inside an action method or the ViewContext if inside an HtmlHelper extension when constructing your menu. Pull out which is the current controller and which is the current action and set that menu item accordingly.
From an action method:
object controller = RouteData.Values["controller"];
object action = RouteData.Values["action"];
object area = RouteData.DataTokens["area"];
From an html helper:
object controller = helper.ViewContext.RouteData.Values["controller"];
object action = helper.ViewContext.RouteData.Values["action"];
object area = helper.ViewContext.RouteData.DataTokens["area"];
Here is a helper I wrote a while back to print a css class to an active menu: http://blog.tomasjansson.com/2010/09/asp-net-mvc-helper-for-active-tab-in-tab-menu/
Related
I have below view in my project,
PolicyScreen.cshtml
The above view has below control,
#Html.ActionLink("OK", "AccountScreen", "AccountUC", new { id= ViewBag.id})
Account controller looks like below,
[ActionName("AccountScreen")]
public ActionResult GetPolicyController(int id)
{
if (viewName='PolicyScreen')
{
//do validation
}
}
If I click OK, I am able to hit AccountUC controller and AccountScreen Action Name properly.
Now I need to know from which view I was navigated to AccountUC controller?
The answer is PolicyScreen, but I don't know how to get this view name in action method,any help?
I wonder why you need this, but you can do this by putting the view name in the action link parameters:
new { id = ViewBag.id, fromView = "PolicyScreen" }
And of course you'll need to alter your action method's signature:
public ActionResult AccountScreen(int id, string fromView)
If you want to get the view name automatically rather than hardcode it, see Retrieve the current view name in ASP.NET MVC?.
If you want the action name rather than the view name, see Get current action and controller and use it as a variable in an Html.ActionLink?.
Try this
#Html.ActionLink("OK", "AccountScreen", "AccountUC",
new { id= ViewBag.id , viewName="replaceCurrentViewNameHere"},null)
Make sure your action method has a parameter to accept the viewname we are sending
[ActionName("AccountScreen")]
public ActionResult GetPolicyController(int id,string viewName)
{
if (viewName=='PolicyScreen')
{
//do validation
}
}
I want to return an object on HTTPGet method and different object in HTTPPost method of the same action method in the controller, but i dont know what to write in the view, which model to get.
Here is the controller code , i have been trying
[HttpGet]
public ActionResult Create()
{
var intSrNo = Convert.ToInt64(TempData["sr_no"]);
MEntities obj_entity = new MEntities();
UDP_get_a_Result obj_proc = obj_entity.UDP_get_a(intSrNo).SingleOrDefault();
return View(obj_proc);
}
[HttpPost]
public ActionResult Create(Table_a obj_a)
{
if (ModelState.IsValid)
{
db.Table_a.AddObject(obj_a);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(obj_a);
}
i'm confused which model to write in view.(Table_a or UDP_get_a_Result) and i want both HttpGet to show values when the page is loaded and HttpPost when the submit is clicked.
View
#model ABC.models.Table_a
#{
ViewBag.Title = "Create";
}
A view can only be strongly typed to a single class. You cannot have different controller actions returning the same view and passing different models to this view. You could use view models: define a class which will hold all the information necessary for this view and then have your controller actions fill this view models and pass it to this view.
I think it would work to have the view typed to some base class (object) and then cast the model to whatever you needed it to be based on get/post. I wouldn't want to maintain it tho. :-D
Currently I have a page with navigation menu. This navigation menu get it items and sub items from database.
I think that it would be easier for me to control it if I make it as a separate controller.
For example:
public class NavigationMenu : Controller
{
public ActionResult Menu()
{
Model model = // Get items and sub items
return View(model);
}
}
Is this right way to make this or I shouldn't do this from some reason?
And if I make it this Menu view will not have any master layout. Should I remove all <html><head><body>... html code from it or not?
We use this pattern, though we call it NavigationController, and the action method is TopTabs. We have it as a [ChildActionOnly], and return a partial view. To render the navigation in the layout, we use #Html.Action().
I'd answer your question with a yes, and render the partial view as a child action in either your layout or your main views:
[ChildActionOnly]
public class NavigationController : Controller
{
public PartialViewResult CommonMenu()
{
Model model = // Get items and sub items
return PartialView(model);
}
}
I am trying to create a RenderAction method on the Master page that will dynamically generate a side bar based on the current controller and action. When the RenderAction is called in the view it is populated with the controller and action of that particular RenderAction Method. For Example, if I am on the controller of “Home” and action of “Index” I am expecting "Home" and "Index" in the GenerateSideBar method. Instead I get the controller of “Home” and action of “RenderSideBar”. Thanks For your Help!
My Master Page View:
<div class="side-bucket">
<%
string Controller = ViewContext.RouteData.Values["Controller"].ToString();
string Action = ViewContext.RouteData.Values["Action"].ToString();
%>
<% Html.RenderAction("RenderSideBar", "Home", new { controller = Controller, action = Action }); %>
Controller Action:
public ActionResult GenerateSideBar(string controller, string action)
{
switch (controller.Trim().ToLower())
{
case "member" :
return View(#"sidebar\MemberSidebar");
default:
break;
}
return null;
}
The problem is that controller and action parameter names are special because used in your routes and will take precedence when the default model binder tries to set their values. Simply rename them like this:
public ActionResult GenerateSideBar(string currentController, string currentAction)
{
...
}
and render it:
<% Html.RenderAction("RenderSideBar", "Home",
new { currentController = ViewContext.RouteData.Values["controller"],
currentAction = ViewContext.RouteData.Values["action"] }
); %>
Now you should get the correct parent action name. Also if this action is intended to be used only as child action you could decorate it with the [ChildActionOnly] attribute.
public ActionResult Index(){
var dataContext = new DataEvidencijaDataContext();
MembershipUser myObject = Membership.GetUser();
string KorisnickoIme = myObject.UserName.ToString();
var user = from i in dataContext.korisniks
where i.korisnik1 == KorisnickoIme
select i;
ViewData.Add("user", user);
return View(user);
}
In master page i put this
<%= Html.RenderPartial("profPredmeti", ViewData["user"])%>
but this is not work
You can use RenderAction for this to delegate menu rendering to some controller. Another option is to have your controller (or base controller class, or action filter) put the menu object into ViewData, and then your master page will do
<% Html.RenderPartial("MenuRenderView", ViewData["menu"]) %>
where MenuRenderView.aspx partial view consumes the menu object from ViewData["menu"]. What does this object contain depends on your database/code.
The approach that I have taken in the past is to have a base controller class from which all the other controllers inherit. In that base controller class, you can add items into ViewData after the controller is initialized:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
ViewData.Add("CommonPageData", CommonPageData);
}
The "CommonPageData" in this case is a property or type CommonPageData (a custom class) whose properties are lazy-loaded. One of the properties is a navigation item collection that is consumed on the master page.
User RenderPartial for the Menu, but you're gonna need to pass in the ViewData the datasource for the menu all the time, a solution is to make an abstract BaseController and to put the datasource in the ViewData in the constructor of that base controller
all the controllers will inherit from the base controller
I have this block sitting in my Site.Master page:
<script runat="server" type="text/C#">
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
MasterModel = SiteMasterViewData.Get();
}
protected SiteMasterViewData MasterModel;
</script>
That Get() method is a static factory method tacked on to the View Data class. All of this is embarrassing but here we are.