I am a noob to mvc.I am using a repository pattern with linq2sql using mvc
Just doing some test to get a clear idea everything around the it.
I am trying to output authors from author table.
public class AuthorsRepository : IAuthorRepository
{
private Table<BK_Author> _authorsTable;
public IQueryable<BK_Author> Authors
{
get { return _authorsTable.AsQueryable<BK_Author>(); }
}
in the controllers
public class AuthorsController : Controller
{
private IAuthorRepository _authorRepo;
public AuthorsController()
{
string connectionString = "";
_authorRepo = new AuthorsRepository(connectionString);
}
public ViewResult List()
{
return View(_authorRepo.Authors.ToList());
}
on the view part
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
<div class="item">
<% foreach (var k in Model)
{ %>
<%: k.Author_Name %>
<%: k.Author_email %>
<%: k.Author_phonenumber %>
<%: k.Author_Website %>
<% }%>
</div>
When I try to run it I am having a compiler exception
"foreach statement cannot operate on variables of type 'BK_Author' because 'BK_Author' does not contain a public definition for 'GetEnumerator'"
Page's model is somehow set to an object of BK_Author and not of AuthorsRepository. Set it to AuthorsRepository and access list of authors using its Authors property.
In your View page, you could simply inherit something like this:
Inherits="System.Web.Mvc.ViewPage<IEnumerable<Authors>>"
or after foreach(var k in Model) you should case k to Authors like:
Authors author = (Authors)k;
Hope this help!!
Related
I created a strongly typed view which view data class is the class called ProductList. I am returning to the view a list object as well that comes from getting all the products by using linq to entitites. Why am I getting an error when trying to use the product.name as shown on the code below on the view. Im very new on this so sorry if my question is bad. Any help would be very appreciated
public class ProductList
{
public IList<Product> Products { get; set; }
}
this is the controller :
public ViewResult List()
{
IQueryable<Product> allproducts= productrepository.selectAll();
return View(allproducts.ToList());
}
and this is the view :
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"Inherits="System.Web.Mvc.ViewPage<TradeIt.Models.ProductListViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
List
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% foreach (var product in Model.Products)
{ %>
<%: Html.LabelFor(product.Name) %>
<% } %>
</asp:Content>
I am getting the next error: The type argument for method 'system.web.mvc.html.labelExtensions.LabelFor... cannot be inferred from the usage . Try specifiying the type arguments explicitly'
change this
"Inherits="System.Web.Mvc.ViewPage" %>
your model is called ProductList, not ProductListViewModel
I am following the NerdDinner part in the Book Professional ASP.NET MVC 2. Currently i am at the part where i need to implement the DinnerFormViewModel and the Renderpartial Dinnerform.
The book contains some errors here so I tried to search on the internet and fix it myself..
I have put the DinnerFormViewModel in the Models folder this is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace NerdDinner.Models
{
public class DinnerFormViewModel : Controller
{
private static string[] _countries = new[]{
"USA",
"Ireland",
"Scotland",
"Namibia"
};
//Properties
public Dinner Dinner { get; private set; }
public SelectList Countries { get; private set; }
//Constructor
public DinnerFormViewModel(Dinner dinner)
{
Dinner = dinner;
Countries = new SelectList(_countries, dinner.Country);
}
// GET: /DinnerFormViewModel/
public ActionResult Index()
{
return View();
}
}
}
Then i have made the DinnerForm.ascx (Partial class):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewPage<NerdDinner.Models.DinnerFormViewModel>" %>
<%: Html.ValidationSummary("Please correct the errors and try again.") %>
<% using (Html.BeginForm()) { %>
<fieldset>
<p>
<%: Html.LabelFor(m => m.Dinner.Title) %>
<%: Html.TextBoxFor(m => m.Dinner.Title) %>
<%: Html.ValidationMessageFor(m => m.Dinner.Title, "*") %>
ETC...
and i have made the edit.aspx as follows:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<NerdDinner.Models.DinnerFormViewModel>" %>
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Edit: <%: Model.Dinner.Title %>
</asp:Content>
<asp:Content ID="Edit" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit Dinner</h2>
<% Html.RenderPartial("DinnerForm"); %>
</asp:Content>
Now if i start the application, an error at <% Html.RenderPartial("DinnerForm"); %> will popup saying:
c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\c8cca855\23406a1e\App_Web_dinnerform.ascx.32d6c807.tczxq3bd.0.cs(166): error CS0030: Cannot convert type 'ASP.views_dinners_dinnerform_ascx' to 'System.Web.Mvc.ViewUserControl'
I think it has something to do with the namespaces, but i can't fix the error, someone faced the same problem or someone here that can help me out?? Thank you!:)
Your partial view should inherit from System.Web.Mvc.ViewUserControl.
ViewPage is for a full view.
This is my model:
public class IndexViewModel
{
public FilterConditions conditions { get; set }
public IEnumerable<SelectListItem> Countries { get; set }
}
public class FilterConditions
{
public string condition11 { get; set }
// ...
}
And I have an Index action method like so:
public ActionResult Index()
{
var model = new IndexViewModel();
// fill the model here with default values
return View(model);
}
The view renders a form with the filterconditions as input types.
Now I want the post back from that form be handled by this action method:
[HttpPost]
public ActionResult Index(FilterConditions model)
{
// do some magic with model and return another view here
}
and this actually works (I put a breakpoint in the method, and it gets called), but the properties of my model are always empty (default values), while they should contain the values which were posted by the form.
When I modify the action method like this:
[HttpPost]
public ActionResult Index(IndexViewModel model)
{
// do some magic with model.conditions and return another view here
}
It all works like it should, but this is not "right" (IMHO), as I don't need the ´Countries´ list on return, I only need the selected country (which is one of the conditions).
What is a nice (best practice) way to make this work without having to take the whole original viewmodel as an input parameter?
Btw, I'm using ASP.NET MVC 2 (I don't think it really matters, as I think it's the same problem in MVC 3, but I'm not entirely sure of that).
(I have been looking around the internet for "best practices" regarding dropdownlists and viewmodels within asp.net mvc, but the different recommendations I found didn't really line up with each other, and a lot is already outdated as well. I didn't find an "official" best practice around this. I hope I'm going in the right direction (having the list as part of my viewmodel), feel free to correct me on this matter if I'm not. Also feel free to point me to "endorsed best practices" about this if you know of any.)
Update:
I found out that I can use the [Bind] attribute with a Prefix of "filterconditions". And this indeed works for this view. But my original problem (I admit, it was not included in my question) is not solved.
It happens that this particular action method is also called from another view (it is an ajax call) where it doesn't have that prefix, in that case it doesn't work any more now. Any suggestions?
I've found the solution.
Apparently, when I use the same name for the parameter variable as the name of the type (the case doesn't have to match), like this:
[HttpPost]
public ActionResult Index(FilterConditions filterConditions)
{
// do some magic with model and return another view here
// now the filterConditions variable actually contains values!
}
Everything works like it should (the values of my filterConditions are not empty/null anymore). Apparently, the default modelbinder uses the name of the parameter as the potential prefix for the binding.
I'm glad I found out, but it would be nice if this is more clearly documented somewhere. It's not obvious at all.
Edit:
On request: this is the code in my view (aspx):
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyProject.Models.IndexViewModel>" %>
<%-- ... more stuff here ... --%>
<% using (Html.BeginForm())
{%>
<%= Html.ValidationSummary(true)%>
<fieldset>
<div class="editor-label">
<%= Html.LabelFor(model => model.FilterConditions.Country)%>
</div>
<div class="editor-field">
<%= Html.DropDownListFor(model => model.FilterConditions.Country, Model.Countries)%>
<%= Html.ValidationMessageFor(model => model.FilterConditions.Country)%>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.FilterConditions.Make)%>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.FilterConditions.Make)%>
<%= Html.ValidationMessageFor(model => model.FilterConditions.Make)%>
</div>
<%-- ... more fields inserted here ... --%>
<p>
<input type="submit" value=" Search... " />
</p>
</fieldset>
<% } %>
Hi fretje: Now I can use your way to solve your problem, First I have two Models "IndexViewModel" & "Index", and the DropDownList(it's doesn't matter, just offer the DropDown items):
public class IndexViewModel : Index
{
//public int value { get; set; }
public List<System.Web.Mvc.SelectListItem> items { get; set; }
}
public class Index
{
public int value { get; set; }
}
class DropDownList
{
public List<System.Web.Mvc.SelectListItem> GetDropDownList()
{
List<System.Web.Mvc.SelectListItem> result = new List<System.Web.Mvc.SelectListItem>();
result.Add(new System.Web.Mvc.SelectListItem
{
Value = "1",
Text = "Apple"
});
result.Add(new System.Web.Mvc.SelectListItem
{
Value = "2",
Text = "Milk"
});
return result;
}
}
And two Controllers is Test() and Test(Models.Index), I pass the IndexViewModel and postback IndexModel:
public ActionResult Test()
{
var result =
new Models.IndexViewModel
{
value = 1,
items = new Models.DropDownList().GetDropDownList()
};
return View(result);
}
[HttpPost]
public ActionResult Test(Models.Index posatback)
{
return View();
}
The View of Test() is:
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-field">
<%: Html.DropDownListFor(m=>m.value, Model.items )%>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
that's work! thank you fretje, I learned one more tech. : )
Maybe you can try
[HttpPost]
public ActionResult Index([Bind(Exclude="Countries")]IndexViewModel model)
{
// do some magic with model.conditions and return another view here
}
Hi~
You don't need to combine the whole SelectListItem to ViewModel, actually your ViewModel just only have a field to store user's choise, integer or string, then use DropDownListFor like:
<%: Html.DropDownListFor(item.WeaponID, MyApplication.Models.DropDownList.GetDropDownList() )%>
please see my post in my blogspot, I use a very simple example to explain:
http://maidot.blogspot.com/2011/04/aspnet-mvc-viewdropdownlistfor.html
let me know if you have any problems : )
This seems like it should be prettty easy - but I just can't get it to work!
I have an enum in my model, which I want to display as a list of checkboxes. The user can select multiple checkboxes, and I want to save this in the database.
So the enum is like so (approx 20 elements unabridged):
public enum ReferrerType
{
[Description("No Data")]
NoData = 9999,
[Description("Father or Mother")]
Parents = 1,
[Description("Brother or Sister")]
Sibling = 2,
[Description("Other")]
Other = 10
}
Whereby the Description is what is shown on the UI, and the numeric value is what is to be saved in the database. The numbers have to remain as listed, as they go directly into a stats package.
I then defined a Referrer class:
public class Referrer
{
public virtual Guid Id { get; private set; }
public virtual ReferrerType{ get; set; }
}
I realise this might be an odd (anti)pattern. I developed it in haste, and am repenting at leisure. Any advice on improving this model would also be much appreciated!
My controller sets up the list:
private static IList<string> GenerateReferrerList()
{
var values = from ReferrerType e in Enum.GetValues(typeof(ReferrerType))
select new { Name = e.ToDescription() };
return values.Select(x => x.Name).ToList();
}
And I use it in my View like this:
<div class="radio-boolean form-field" id="Referrers">
<p class="form-field-attribute"> <span class="label">Referred By </span> </p>
<% for (var i = 0; i < ((IList<string>)ViewData["ReferrerList"]).Count; i++)
{ %>
<p class="form-field-value">
<%= Html.CheckBox(string.Format("Referrers[{0}].Type", i) ) %>
<label for="Referrers"> <%= ((IList<string>)ViewData["ReferrerList"])[i]%></label>
</p>
</div>
And it doesn't work! I guess I'm missing something obvious, but I can't work out what. There are no errors - just an empty database table where referrers should be...
As always, any help much appreciated!
Let's take a moment and see what do we need here. We need to show a form which will contain multiple checkboxes (one for each value of the enum) and an associated label (this label should come from the Description attribute use on the enum). When this form is submitted we want to fetch all the values that the use has checked.
So as always once we have clear definition of what we are trying to do we introduce our view model:
public class MyViewModel
{
public bool IsChecked { get; set; }
public ReferrerType ReferrerType { get; set; }
public string Text { get; set; }
}
Then we write a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = Enum.GetValues(typeof(ReferrerType)).Cast<ReferrerType>().Select(x => new MyViewModel
{
ReferrerType = x,
Text = x.ToDescription() // I guess that's an extension method you wrote
});
return View(model);
}
[HttpPost]
public ActionResult Index(IEnumerable<MyViewModel> model)
{
...
}
}
And finally a strongly typed view corresponding to the Index action of our controller (~/Views/Home/Index.aspx):
<% using (Html.BeginForm()) { %>
#Html.EditorForModel()
<input type="submit" value="OK" />
<% } %>
and the last part is the corresponding editor template (~/Views/Home/EditorTemplates/MyViewModel.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<AppName.Models.MyViewModel>" %>
<%= Html.CheckBoxFor(x => x.IsChecked) %>
<%= Html.HiddenFor(x => x.ReferrerType) %>
<label><%: Model.Text %></label>
Now when this form is submitted inside the POST index action you would get a list of all enums with a corresponding boolean value indicating whether the user checked it or not.
OT: Don't perform excess actions:
return (from e in Enum.GetValues(typeof(ReferrerType))
select e.ToDescription()).ToList();
or just
return Enum.GetValues(typeof(ReferrerType)).Select(e => e.ToDescription()).ToList();
I'm currently working my way through the MVC Music Store tutorial. I'm stuck on page 53 at the moment and I was wondering if someone could help me out.
I'm currently receiving the following two errors:
'object' does not contain a definition for 'Artists'
'object' does not contain a definition
for 'Genres'
I think I've looked at it for too long now and I can't spot my error. A fresh pair of eyes may do the trick!
Here is the aspx file in which the error occurs:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcMovies1.ViewModels.StoreManagerViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit</h2>
<% using (Html.BeginForm())
{ %>
<%: Html.ValidationSummary(true)%>
<fieldset>
<legend>Edit Album</legend>
<%: Html.EditorFor(model => model.Album,
new object{ Artists = Model.Artists, Genres = Model.Genres }) %>
<p><input type="submit" value="Save" /></p>
</fieldset>
<% } %>
</asp:Content>
And here is the class that this page should be calling from, so to speak:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MvcMovies1.Models;
namespace MvcMovies1.ViewModels
{
public class StoreManagerViewModel
{
public Album Album { get; set; }
public List<Artist> Artists { get; set; }
public List<Genre> Genres { get; set; }
}
}
PS - I realise some of my names are MvcMovies1, I called it that by mistake but everything is referenced accordingly.
Replace:
new object{ Artists = Model.Artists, Genres = Model.Genres }
With:
new { Artists = Model.Artists, Genres = Model.Genres }
In other words, you want to create a new anonymous type. Your syntax above actually attempts to create a new bare object and assign values to the nonexistent properties on object: "Artists" and "Genres".