This seemed easier in Web Forms; I'd have a user control, with the logic in the code-behind, and I could just drop it on a page.
But apparently code-behinds are a no-no in MVC, and the logic is in controllers. I'm a little confused about how logic for a user control is "wired up".
I want to display an RSS Feed user control. So I have a page:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<p>
<% Html.RenderPartial("RssFeed"); %>
</p>
</asp:Content>
I have my user control:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewPage<SyndicationFeed>" %>
<%# Import Namespace="System.ServiceModel.Syndication" %>
<p>
<%: ViewData.Model.Title.Text %>
</p>
<div>
<% foreach (var item in ViewData.Model.Items)
{
string url = item.Links[0].Uri.OriginalString;
%>
<p><a href='<%= url %>'><b><%= item.Title.Text %></b></a></p>
<% } %>
</div>
And I have this code that I need to run to get the rss data:
using (XmlReader reader = XmlReader.Create(ConfigurationManager.AppSettings["RssFeed"]))
{
SyndicationFeed rssData = SyndicationFeed.Load(reader);
return View(rssData);
}
But where does it go? In the controller for the page that contains the control?
To sum it up, this is how you can do it
[HttpGet, ChildActionOnly]
// put this in RssController
public ActionResult RssFeed()
{
// prepare the model
SyndicationFeed rssData;
using (XmlReader reader = XmlReader.Create(ConfigurationManager.AppSettings["RssFeed"]))
{
rssData = SyndicationFeed.Load(reader);
}
return PartialView(rssData);
}
Usage:
<% Html.RenderAction("RssFeed", "Rss"); %>
And put a check into your ASCX if the Model you are sending in is null and if so, skip everything so it won't render anything. If you leave it like you have it now, it will end in an exception if the Model sent in is null.
Based on my understanding.... Yes, it can go in the controller in the page that contains the control. The partial can use the parent's ViewModel
See here (the bit on Partial Views)
http://msdn.microsoft.com/en-us/library/dd410123.aspx
EDIT
To include your RSS feed
If my controller were named RssController and it had a ViewResult method named RssFeed, I'd include the following on the .Master.
This causes the RssController to get invoked and return the view for your partial (assuming that's what View(rssData) sent back.
In ASP.NET MVC 2+, you can use Html.RenderAction to render an action's result inline.
Giving the action a [ChildActionOnly] attribute will prevent users from navigating to the action normally, making it usable only in this kind of "child" context.
I had a vaguely similar problem (using Razor view engine) which I solved by putting the code into the page since there wasn't anywhere else I wanted to put it. Mine actually related to rendering a menu.
The trick is to use the #functions { ... } construct.
Some pertinent info about the layout stuff here: http://weblogs.asp.net/scottgu/archive/2010/10/22/asp-net-mvc-3-layouts.aspx
Kind of like this in your case (not exactly right; it's late and I'm not on my dev box, but it hopefully gives the idea). That way you don't need any RSS controller at all if you are only doing this small piece of RSS related stuff.
#foreach (var item in RssFeed().Items)
{
<p><a href='#item.Links[0].Uri.OriginalString'><b>#item.Title.Text</b></a></p>
}
#functions {
public SyndicationFeed RssFeed()
{
using (XmlReader reader = XmlReader.Create(ConfigurationManager.AppSettings["RssFeed"]))
{
return SyndicationFeed.Load(reader);
}
}
}
Related
I want to call one div when the page is default.aspx and to call same div at the same time when the page is another page than default.I have done something like this but is not doing correctly.
<% if(string.Compare(Request.Url.LocalPath,"/default.aspx")==0 || string.Compare(Request.Url.LocalPath,"/") ==0)
{%>
<div class="temples" >
<% } %>
<% else
{ %>
<div class="temples" style="display:none";>
<% } %>
You can try like this:
string s = this.Page.Request.FilePath;
This will get you the current request URL from within the master page
Also check the IsMasterPage property:
Gets a value that indicates whether or not a child element in the
viewer should be used as a master page.
There is a property IsMasterPage to define whether your control element associated to master page. Below is a link to get more information.
DocumentViewerBase.IsMasterPage
I want to insert a user control on to a master page
The user control is a basic menu that lists categories of items
I want to pull the category list dynamically from SQL Server
I can do this in web forms using code behind, but how do you go about this in MVC?
Thank you
Categories.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<ul>
<% foreach (string category in Model.Categories ) { %>
<li>
<%= Html.Encode(category) %>
</li>
<% } %>
</ul>
I would make a base controller for all the controllers that will use your MasterPage. In that base controller I would load up your list of data to create the menu (from a cache, sql, whatever) and store it in ViewData.
If you want to you could also make a base model for all your models that will be loading your views based on the controller as well and then you could just load it directly into the models that extend this base class.
Assuming your went the easier ViewData route, in your user control you can just access the ViewData and load your menu since you can assume that all your contorllers will have pre-loaded this data.
this is in your Controller:
ViewData["CategoryList"] = _categoryService.GetCategoryList();
this exists in a file called NameOfMyPartial.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% foreach (var category in (IList<Category>)ViewData["CategoryList"])) { %>
// do stuff with category
<% } %>
Then in your Master page:
<% RenderPartial("NameOfMyPartial"); %>
I've began working with asp.net mvc very recently and I've ran into a problem.
I've got an aspx page which renders a few ascx pages. What I'd like to do is declare a global var at the aspx page so it is visible to all its childs. I tried <% var i = 0; %> but it wasn't visible at the child pages.
What could I do?
variables from a aspx page are not shared with the partial views.
The view is just a representation of a piece of data. You have to pass the data as a Model to each view you want to render, whether it's a plain View or a PartialView.
<% Html.RenderPartial("ViewName", Model, ViewDataDictionnary) %>
If you want to pass a variable to a partial view, I would strongly recommend you to add this parameter to the model of the partial view, rather that to pass it additionally via the ViewDataDictionnary.
You can add it to the ViewData and then pass the ViewData to the ascx with
<% Html.RenderPartial("ViewName", Model, ViewData) %>
see msdn on RenderPartial
So in your aspx page you'd do something like
<% ViewData["i"] = 0; %>
And in your userControl you'd just retrive it and use it as you want
<% int i = (int)ViewData["i"] %>
Another way would be to use RenderAction eand pass it as a parameter... so we'd need to know how you display your ascx.
see msdn on RenderAction
How do I create a menu in a ASP.NET MVC2 Master Page, dynamically based on the current user's "role"?
The simplest and most straightforward way would be to simply add an if statement in the view markup:
<% if (Page.User.IsInRole("Admin")) { %>
<%= Html.ActionLink("Admin Tools Index", "Index", "Admin") %>
<%= Html.ActionLink("Admin Dashboard", "Dashboard", "Admin") %>
<% } %>
Or, you can separate out several items pertaining to a specific role into a partial view:
<% if (Page.User.IsInRole("Admin")) { %>
<% Html.RenderPartial("AdminMenu"); %>
<% } %>
I'm not sure about MVC but in 'normal' ASP.NET it is possible to select a MasterPage at runtime.
If you are using the sitemap file to generate menus then you can probably do it in there. If not, then it depends.
bascially, how should i do it now that using the asp:listview control is out of the question?
i am migrating from webforms to mvc and former implementation was in <asp:ListView...> so how should i do it now in terms of best user experience for the user? ie: i will need to ajax everything.
thanks
You should use the standard list box now. If you need to return the list from your controller you return a SelectList [i think that's it].
To ajax the select list you can use say jQuery to add click and change events which will then call actionresults in your controller.
Edit
Ah right, there are a couple of ways. You could use a jQuery grid which will display the rows and allow you to have edit delet buttons. You then post back to an action, make the changes and come back. All Ajax of course.
The other way might be to write a couple of PartialViews. The first loops through your collection and the second displays the row. The last one would have say the buttons or a check box or whatever.
Then you again post back, via ajax, to an action result, make the changes and come back.
Your action result can return a fully rendered partial view so after you make your changes, return a new partial view of your data rows and replace the old with the new.
edit 2
if you want code, leave a comment and i'll provide
edit 3
There are a bunch of jQuery grids out there, just google it.
As for partial views something like this would work;
HTML Partial View 1 called BenefitList;
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IQueryable<Models.Benefit>>" %>
<% foreach(Benefit benefit in Model){ %>
<% Html.RenderPartial("Benefit", benefit); %>
<% } %>
HTML Partial View 2;
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Models.Benefit>" %>
<fieldset class="Benefit benefit" id="<%= Model.Id %>">
<legend><label class="Title"><%= Html.Encode(Model.Title) %></label> <a class="BenefitDescriptionView" href=".">View</a><a class="BenefitDescriptionEdit" href=".">Edit</a></legend>
<div class="BenefitDescription hidden">
<%= Html.Encode(Model.Description) %>
</div>
</fieldset>
Some jQuery for you to do a post to an action result;
function jQueryDeleteBenefit() {
$.post("/Home/jQueryDeleteBenefit", { Id: YOURID },
function(NEWHTML) {
$('.EditProductContainer').html(NEWHTML);
});
}
An action result;
[AcceptVerbs(HttpVerbs.Post)]
public void jQueryDeleteBenefit(int id
{
//delete item
return PartialView("BenefitList", AllMyBenefits);
}