asp.net mvc tabs inside tabs - asp.net

I have created an asp.net mvc2 project using the standard visual studio template which contains 2 tabs Home and About.
In the Home tab I want to add sub tabs from here http://labs.silverorange.com/archive/2003/september/simplecsstabs
How do I do this : can I create sub-component and sub-controller or what ?
I'm beginner at asp.net and MVC so can't there be a beginner solution that is close as much as possible to t to the plain css tabs ?

You could write a custom HTML helper that will generate those sub tabs based on the current controller and action. Here's an example to get you started:
public static class HtmlExtensions
{
public static MvcHtmlString SubTabs(this HtmlHelper htmlHelper)
{
var currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action");
var currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller");
// TODO: base on the current action and controller
// generate proper tabs
var ul = new TagBuilder("ul");
var lis = new StringBuilder();
var li = new TagBuilder("li");
li.InnerHtml = htmlHelper.ActionLink("sub 1", "sub1", "home").ToHtmlString();
lis.AppendLine(li.ToString());
li = new TagBuilder("li");
li.InnerHtml = htmlHelper.ActionLink("sub 2", "sub2", "home").ToHtmlString();
lis.AppendLine(li.ToString());
ul.InnerHtml = lis.ToString();
return MvcHtmlString.Create(ul.ToString());
}
}
and then in your view:
<%= Html.SubTabs() %>
Obviously in my example everything is hardcoded. You might want to keep some centralized hashtable of sub tabs corresponding to given controller and action. Once you get the proper markup simply apply the CSS from the site you are referred to in your question and you are good to go.

Related

Failing to reference another model in my view asp.net mvc

I am trying to display Youtube videos in my landing page. I know the code works because in another view it works.
In my landing page I am referencing a model that calls my blog posts and so I cant reference another model in my landing page
The error i get says the current model doesn't contain 'GetEnumerator'. If i add another model, I get an error saying a view can only reference one model.
This is how I display my blog posts and video in the landing page with 'model ' and 'videos'.
public ActionResult landing()
{
var model = new Stream.FeedViewModel();
var videos = WeLove.Net.Models.Stream.YouTubeHelper.GetVideos();
XmlReaderSettings settings = new XmlReaderSettings();
settings.XmlResolver = null;
settings.DtdProcessing = DtdProcessing.Ignore;
settings.DtdProcessing = DtdProcessing.Parse;
using (var reader = XmlReader.Create("https://takeonemisu.wordpress.com/feed",settings))
{
var feed = SyndicationFeed.Load(reader);
foreach (var post in feed.Items.Take(3))
{
model.Posts.Add(post);
}
}
return View(model);
}
I unfortunately can only get one to run at a time in a view.
Please help
Use child actions:
Controller
[ChildActionOnly]
public ActionResult VideoList()
{
var videos = // get videos;
return PartialView(videos);
}
[ChildActionOnly] ensures that this action can only be called as a child and not directly via a URL in the browser. If you want to serve it up at a particular URL as well, you can always remove this attribute, but then you should most likely branch over boolean values of ControllerContext.IsChildAction and/or Request.IsAjaxRequest to either return a PartialView or View as needed.
VideoList.cshtml
#model Namespace.To.VideoModel
<ul>
#foreach (var video in Model)
{
<li>#video.Title</li>
}
</ul>
Obviously the partial view HTML can be whatever you want. I just made an unordered list as an example
Post View
#Html.Action("VideoList")

How to render html code with asp.net class

I need to be able to add a dynamic html code to a random cshtml page using my class:
public class HTMLRenderClass
{
//--here I generate html code
public void RenderControll()
{
LiteralControl ControlGroup = new LiteralControl();
ControlGroup.Text = "<h1>Here will be html code generated above</h1>";
Page p = HttpContext.Current.Handler as Page;
if (p != null) p.Controls.Add(ControlGroup);
else { throw new UserFriendlyException("Page still null"); }
}
}
so that inside cshtml I could call it like
#{
HTMLRenderClass c = new HTMLRenderClass();
c.RenderControll();
}
But the problem is that I don't know how to add my html to the page I need, because "HttpContext.Current.Handler as Page" is always null. Are there any solutions of that situation in which I still could use c.RenderControll() method without passing any "Page object" parameters?
If not, then what exactly should I pass to my class to place my dynamic html block inside static one?

Global Permissions-Based Navigation Sharepoint Foundation 2010

I am using SharePoint Foundation 2010 and I would like to create a multilevel navigation. (Similar to what the publishing site allows in SharePoint Standard. I realize that this could probably be built using a custom sitemap provider, which I have looked into.
The kicker here, is that I would like for it only show the pages and sites in which the logged in user has permissions to.
Currently, I have began developing a web part. Inside this web part I have written some c# code to loop through and get all the sites and subpages ( and check if the user has permissions) and then add them to a label. Eventually I would like to add them to either an asp:menu or create a and then use some css or jquery to manipulate it to do the drop down features.
Here is some of my code:
using (SPWeb oWebsite = new SPSite(webUrl).OpenWeb())
{
SPWebCollection collWebsite = oWebsite.Webs;
foreach (SPWeb subSite in collWebsite)
{
if (subSite.DoesUserHavePermissions(SPContext.Current.Web.CurrentUser.LoginName, SPBasePermissions.Open))
{
Label1.Text += SPEncode.HtmlEncode(subSite.Title) + "<BR>";
}
SPList pagelist = subSite.Lists["Site Pages"];
foreach (SPListItem item in pagelist.Items)
{
if (item.DoesUserHavePermissions(SPContext.Current.Web.CurrentUser, SPBasePermissions.Open))
{
Label1.Text += item.Name + "<BR>";
}
}
Label1.Text += "<BR><BR>";
subSite.Close();
}
Label1.Text += "<BR><BR><BR><BR>";
}
}
Instead of adding the site or page to the label, here is where I would like to create the list. The ultimate goal would be to place this web part onto the masterpage and allow for it to give the users some navigation based on permissions.
I also found some css to allow the multilevel navigation to work by adding elements simply as a inside of an The only issue here is that once I placed this onto the masterpage, The 2nd level displayed when I hovered over the first item, but would disappear upon moving my mouse there. (This worked great when the webpart was placed onto a page itself)
Am I on the right track here or is there another method that may work just as well or even better?
TIA.
SPSecurity.RunWithElevatedPrivileges(delegate
{
SPSite oSiteCollection = SPContext.Current.Site;
using (SPWeb oWebsite = new SPSite(webUrl).OpenWeb())
{
SPWebCollection collWebsite = oWebsite.Webs;
foreach (SPWeb subSite in collWebsite)
{
var newItem = new MenuItem();
if (subSite.DoesUserHavePermissions(SPContext.Current.Web.CurrentUser.LoginName, SPBasePermissions.Open))
{
newItem.NavigateUrl = subSite.Url;
newItem.Text = SPEncode.HtmlEncode(subSite.Title);
newItem.Value = SPEncode.HtmlEncode(subSite.Title);
}
SPList pagelist = subSite.Lists["Site Pages"];
foreach (SPListItem item in pagelist.Items)
{
if (item.DoesUserHavePermissions(SPContext.Current.Web.CurrentUser, SPBasePermissions.Open))
{
var subItem = new MenuItem();
subItem.Value = SPEncode.HtmlEncode(item.Name);
subItem.Text = SPEncode.HtmlEncode(item.Name);
subItem.NavigateUrl = item.Url;
newItem.ChildItems.Add(subItem);
}
}
mnNAv.Items.Add(newItem);
subSite.Close();
}
}
});

Central HTML templates to prevent duplicate presentation code in ASP.NET MVC

In my application I have a lot of UI elements (particuarly buttons) where I am repeating the same code over and over.
For example in multiple views I might have an edit button that is created with the following code:
#Html.ActionLink("Edit", "Edit", "SomeController", null, new { #class="button large blue" });
The problem here is that I am hard coding the label and styling, so if I want to make changes to the button styling or label, I would have to make them in multiple views. This would be tedious to do, as I would have to track down every button.
So now I am looking at creating a templating mechanism, where I can define a button template in a central area and bring it in to any view I want to use it in.
I have considered two options, which I have tried to sketch out in semi-real world code below.
My question is, am I on the right track here? Which option would be better and for which reasons? Is there already something out there I could consider using, or is there another way which I haven't thought of?
Thanks for your help.
Web.Config Templates
Create a custom class that can bring in template configuration from web.config file. For example:
<ui.HtmlTemplates>
<add templateKey="FormCancel" tag="a" class="form-button large black" />
<add templateKey="FormSave" tag="input" type="submit" class="form-button large green" />
</ui.HtmlTemplates>
And then could call them in with syntax such as this (method signature is contrived)
#HtmlTemplates.Build("FormCancel", Url.Action("Index", "Home"))
Partial View Templates
Create strongly typed partial views with the template I want.
ViewModel
public class UiButtonModel
{
public string Url{ get; set; }
}
Partial View
// Assume the file is called "_Button_FormCancel"
#Model path.to.model.directoy.UiButtonModel
Cancel
Use
#Html.Partial("_Button_FormCancel", new UiButtonModel(){Url = Url.Action("Index", "Home"));
Another option is to create extension methods off of HtmlHelper to create prepackaged HTML output using code:
using System.Web.Mvc;
using System.Web.Routing;
public static class MyHtmlExtensions
{
public static string SaveButton(this HtmlHelper helper, string title = "Save", IDictionary<string, object> htmlAttributes = null)
{
var builder = new TagBuilder("button");
builder.Attributes.Add("type", "button");
builder.AddCssClass("form-button");
builder.AddCssClass("large");
builder.AddCssClass("green");
if (htmlAttributes != null) builder.MergeAttributes(htmlAttributes);
builder.SetInnerText(helper.Encode(title));
return builder.ToString();
}
public static string CancelButton(this HtmlHelper helper, string title = "Cancel", string actionName, string controllerName, RouteValueDictionary routeValues = null, IDictionary<string, object> htmlAttributes = null)
{
var urlHelper = new UrlHelper(helper.ViewContext.RequestContext, helper.RouteCollection);
var builder = new TagBuilder("a");
builder.Attributes.Add("href", urlHelper.Action(actionName, controllerName, routeValues));
builder.AddCssClass("form-button");
builder.AddCssClass("large");
builder.AddCssClass("green");
if (htmlAttributes != null) builder.MergeAttributes(htmlAttributes);
builder.SetInnerText(helper.Encode(title));
return builder.ToString();
}
}
Then just make sure the namespace of MyHtmlExtensions is either added to your page directly, or included in all pages via web.config, and use it like this in your view (razor syntax):
<div class="form-buttons">
#Html.CancelButton("Index", "Home")
#Html.SaveButton()
</div>
This method is particularly well suited for creating output consistently across several solutions, as all you need to do is reference the containing assembly and import the namespace.
I create these kinds of templates and put them in my Views/Shared folder.
I have templates like:
AddButton.cshtml
DeleteButton.cshtml
SaveButton.cshtml
...
Then, when I need to call one of them in whatever View, I just call this for example:
#Html.Partial("SaveButton");
Using T4MVC, it gets even better with compile time checking (no more literal strings):
#Html.Partial(MVC.Shared.Views.SaveButton)
Doing so I have a common/central place to change a specific button config. No need to go view after view to change something.
This is the problem that css was designed to handle. I fail to understand the problem. If you want to make changes, you change the CSS and it affects all the buttons that have that styling.
Part of your problem is that you're using style like "blue". If you want to change it to red, you have to change it everywhere.
Instead, you should have a class for the button, then you can simply change the button style and you don't have to worry about redefining blue to red.

ASP.NET MVC2: modifying master css property depending on query string parameter

I am migrating a web site to a new one using ASP .NET MVC2.
In the original site, master page has code-behind to check a query string parameter value. Depending on this value, code-behind dynamically modify some CSS property to hide / display master page elements.
As MVC2 has no code-behind because we are supposed to perform everything in the controllers, how should I proceed in this case ?
I see this : asp.net mvc modifying master file from a view
It partially answers my needs but the query string processing is common to all pages. How can I move this processing in a common code section ?
Regards.
A helper method looks like a good place:
public static class HtmlHelperExtensions
{
public static string GetCss(this HtmlHelper htmlHelper)
{
// read some request parameter
// here you also have access to route data so the
// parameter could be part of your custom routes as well
var foo = htmlHelper.ViewContext.HttpContext.Request["foo"];
// based on the value of this parameter
// return the appropriate CSS class
return (foo == "bar") ? "barClass" : "fooClass";
}
}
And somewhere in your master page:
<body class="<%= Html.GetCss() %>">
Or if you are always going to apply it to the body tag only it might be more appropriate to do this in order to reduce the tag soup:
public static class HtmlHelperExtensions
{
public static MvcHtmlString StartBody(this HtmlHelper htmlHelper)
{
var body = new TagBuilder("body");
var foo = htmlHelper.ViewContext.HttpContext.Request["foo"];
var bodyClass = (foo == "bar") ? "barClass" : "fooClass";
body.AddCssClass(bodyClass);
return MvcHtmlString.Create(body.ToString(TagRenderMode.StartTag));
}
}
and in your master page at the place of the body tag:
<%= Html.StartBody() %>
I can think of two solutions to this:
Derive your controllers from one controller base and set the ViewData parameter there depending on posted Form values
Don't use ViewData at all, but simply look for the form value in the view (using HttpContext.Current)
The second method violates the MVC pattern. IMO it is still acceptable in some scenarios, for example I am using this approach to highlight the currently selected item in a navigation menu.

Resources