Ayman
Ayman

Reputation: 576

How to Merge two views in one view with Asp.net MVC4?

I added a new Controller then I selected the following options:

I got a folder of views which includes by default: Index, Creat, Edit, Detailes, and Delete.

Everything is working fine to here.

My problem that I'm trying to merge the codes of Create view with the codes of Index view(Two views in one).

The Error which i get:

Compiler Error Message: CS1061: 'System.Collections.Generic.IEnumerable' does not contain a definition for 'Title' and no extension method 'Title' accepting a first argument of type 'System.Collections.Generic.IEnumerable' could be found (are you missing a using directive or an assembly reference?)

Here is my Merged View (Index.cshtml):

@model IEnumerable<ReMvc.Models.Movie>

@{
ViewBag.Title = "Index";
}

<h2>Index</h2>

@using (Html.BeginForm()) {
@Html.ValidationSummary(true)

<fieldset>
    <legend>Movie</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.Title)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Title)
        @Html.ValidationMessageFor(model => model.Title)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.ReleaseDate)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.ReleaseDate)
        @Html.ValidationMessageFor(model => model.ReleaseDate)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.Genre)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Genre)
        @Html.ValidationMessageFor(model => model.Genre)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.Price)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Price)
        @Html.ValidationMessageFor(model => model.Price)
    </div>

    <p>
        <input type="submit" value="Create" />
    </p>
    </fieldset>
    }

 @foreach (var item in Model) {
 <tr>
    <td>
        @Html.DisplayFor(modelItem => item.Title)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.ReleaseDate)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Genre)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Price)
    </td>
 </tr>
}

</table>

Here is my controller: I renamed 'Create' ActionResult to Index

namespace ReMvc.Controllers
{
public class MoviesController : Controller
{
    private MovieDbContext db = new MovieDbContext();

    //
    // GET: /Movies/

    public ActionResult Index()
    {
        return View(db.Movies.ToList());
    }



    [HttpPost]
    public ActionResult Index(Movie movie)
    {
        if (ModelState.IsValid)
        {
            db.Movies.Add(movie);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(movie);
    }
}

And here is my Model: using System; using System.Data.Entity;

namespace ReMvc.Models
{
public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
}

public class MovieDbContext : DbContext
{
    public DbSet<Movie> Movies { get; set; }
}
}

I'm beginner with MVC and i stuck here for more than 4 days.. please help.

Upvotes: 1

Views: 3777

Answers (1)

Jamie Rees
Jamie Rees

Reputation: 8183

Well to start your model is a type of IEnumerable<ReMvc.Models.Movie>.

So it's complaining that IEnumerable<T> does not have a method or property called Title:

 @Html.LabelFor(model => model.Title)

'System.Collections.Generic.IEnumerable' does not contain a definition for 'Title' and no extension method 'Title' accepting a first argument of type 'System.Collections.Generic.IEnumerable' could be found

If you didn't mean to use an IEnumerable<T> for the Model so change it to:

@model ReMvc.Models.Movie

If you did mean to use a type of IEnumerable<T> then you will need to loop over your items to access them:

@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
@foreach(var movie in Model)
{
<fieldset>
    <legend>Movie</legend>

    <div class="editor-label">
        @Html.Label(movie.Title)
    </div>
    <div class="editor-field">
        @Html.Editor(movie.Title)
        @Html.ValidationMessage(movie.Title)
    </div>
}

I would also recommend that you do not have the data access in your presentation layer (your controller). Look at separating out your data access from your UI.

If you want to use a type of IEnumerable<T> and a type of ReMvc.Models.Movie in the same view? You will have to do something similar to the following.

You could create a new type and use this:

public class MovieViewModel()
{
    public ReMvc.Models.Movie Movie { get; set; }
    public IEnumerable<ReMvc.Models.Movie> MovieCollection { get; set; }
}

Then you can pass that into your view

@model MovieViewModel

In your controller you just do this:

public ActionResult Index()
{
    var model = new MovieViewModel() 
    {
        MovieCollection = db.Movies.ToList(),
    };
    return View(model);
}

[HttpPost]
public ActionResult Index(Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Movies.Add(movie);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    var model = new MovieViewModel()
    {
        Movie = movie,
    };
    return View(movie);
}

The downside to this is in your view you will now need to check if one is null (Because with your code, one property will always be null either Movie or MovieCollection). I would recommend splitting out your views and use a different Action Method name e.g. Details.

Upvotes: 4

Related Questions