niko619
niko619

Reputation: 453

Asp.net two models in one view

I'm trying to get 2 models to show in 1 view but it is not working. I have tried lots of different ideas from Google but none have worked so far.

There is no error in the Error List. But when I start it I get this error.

The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Namespace.Models.Class1]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Namespace.Models.ParentClass]'.

I have a parent class containing the to child classes. If i use the @model IEnumerable<> directly at the child class it works, but not when pointed at the parent.

What am I doing wrong?

EDIT

Ok so these are my files.

Model1.cs

public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }

Model2.cs

public int AnotherProperty1 { get; set; }
public int AnotherProperty2 { get; set; }

ViewModel.cs

public IEnumerable<Model1> Model1 { get; set; }
public IEnumerable<Model2> Model2 { get; set; }

HomeController.cs

private ConnectContext db = new ConnectContext();
public ActionResult Index()
{
var model = from m in db.model select m;
model = db.model.OrderByDescending(m => m.ID);

return View(db.model.ToList());
}

Index.chstml

@model IEnumerable<Namespace.Models.ViewModel>

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

Now with the files like this my error message is

CS1061: 'System.Collections.Generic.IEnumerable<Namespace.Models.Model1>' does not contain a definition for 'Cover' and no extension method 'Cover' accepting a first argument of type 'System.Collections.Generic.IEnumerable<Namespace.Models.Model1>' could be found (are you missing a using directive or an assembly reference?)

Upvotes: 0

Views: 365

Answers (4)

niko619
niko619

Reputation: 453

Finally I got this working. I had to change my ViewModel, Controller and View.

ViewModel.cs (From IEnumerable to List)

public List<Model1> Model1 { get; set; }
public List<Model2> Model2 { get; set; }

HomeController.cs

private ConnectContext db = new ConnectContext();
public ActionResult Index()
   {
      ViewModel vm = new ViewModel();
      vm.Model1 = (from m in db.Model1 select m).OrderByDescending(x => x.ID).Take(3).ToList();
      vm.Model2 = (from t in db.Model2 select t).OrderByDescending(x => x.ID).Take(3).ToList();

      return View(vm);
   }

Index.cshtml (So here I removed the IEnumerable and then each Foreach connects to each Model)

@model Namespace.Models.ViewModel

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

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

Upvotes: 0

Louis Michael
Louis Michael

Reputation: 398

Try this:

public class FirstModel
{
    public int Id { get; set; }
    public string SomeProperty { get; set; }
}

public class SecondModel
{
    public int Id { get; set; }
    public string SomeOtherProperty { get; set; }
}

public class ViewModel
{
    public FirstModel MyFirstModel { get; set; }
    public SecondModel MySecondModel { get; set; }
}

In your Controller:

private ConnectContext db = new ConnectContext();
public ActionResult Index()
{
    FirstModel firstModel = //Set FirstModel Value;
    SecondModel secondModel = //Set SecondModel Value;

    ViewModel viewModel = new ViewModel(){
        FirstModel = firstModel,
        SecondModel = secondModel
    }

    return View(viewModel);
}

Upvotes: 0

Kritner
Kritner

Reputation: 13765

What about just making a model class with properties that makes up the two classes you need for your view?

E.g.

public class FirstModel
{
    public int Id { get; set; }
    public string SomeProperty { get; set; }
}

public class SecondModel
{
    public int Id { get; set; }
    public string SomeOtherProperty { get; set; }
}

public class ViewModel
{
    public FirstModel MyFirstModel { get; set; }
    public SecondModel MySecondModel { get; set; }
}

Then in your view you use a model of ViewModel.

Upvotes: 2

UtopiaLtd
UtopiaLtd

Reputation: 2590

If you have two and only two classes you want to pass in, have you considered using a tuple?

For example:

On the controller end,

var model = new Tuple<ModelType1, ModelType2>(yourModel1, yourModel2);
return View(model);

On the view end, you'll want this at the top, along with any using statements you may need:

@model Tuple<ModelType1, ModelType2>

To access each part in the view, @Model.Item1 will be your ModelType1 and @Model.Item2 will be your ModelType2.

If you wind up with more than two classes, it might be a good idea for you to make a ViewModel class with properties for the various types you want to include. (You can also cop out and add properties to the ViewBag.)

Upvotes: 4

Related Questions