Wiele modeli w widoku

Chcę mieć 2 Modele w jednym widoku. Strona zawiera zarówno LoginViewModel jak i RegisterViewModel.

Np.

public class LoginViewModel
{
    public string Email { get; set; }
    public string Password { get; set; }
}

public class RegisterViewModel
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
}

Czy muszę zrobić kolejny ViewModel, który przechowuje te 2 Viewmodele?

public BigViewModel
{
    public LoginViewModel LoginViewModel{get; set;}
    public RegisterViewModel RegisterViewModel {get; set;}
}

Chcę, aby atrybuty walidacji zostały przekazane do widoku, dlatego potrzebuję ViewModels.

Czy nie ma innej drogi takiej jak (Bez BigViewModel):

 @model ViewModel.RegisterViewModel
 @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
 {
        @Html.TextBoxFor(model => model.Name)
        @Html.TextBoxFor(model => model.Email)
        @Html.PasswordFor(model => model.Password)
 }

 @model ViewModel.LoginViewModel
 @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
 {
        @Html.TextBoxFor(model => model.Email)
        @Html.PasswordFor(model => model.Password)
 }
Author: Barrosy, 2011-01-22

10 answers

Jest wiele sposobów...

  1. With your BigViewModel robisz:

    @model BigViewModel    
    @using(Html.BeginForm()) {
        @Html.EditorFor(o => o.LoginViewModel.Email)
        ...
    }
    
  2. Możesz utworzyć 2 dodatkowe widoki

    Login.cshtml

    @model ViewModel.LoginViewModel
    @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
    {
        @Html.TextBoxFor(model => model.Email)
        @Html.PasswordFor(model => model.Password)
    }
    

    I zarejestruj się.cshtml same thing

    Po utworzeniu musisz renderować je w widoku głównym i przekazać je viewmodel / viewdata

    Więc może być tak:

    @{Html.RenderPartial("login", ViewBag.Login);}
    @{Html.RenderPartial("register", ViewBag.Register);}
    

    Lub

    @{Html.RenderPartial("login", Model.LoginViewModel)}
    @{Html.RenderPartial("register", Model.RegisterViewModel)}
    
  3. Korzystanie z ajax części swojej strony internetowej stają się bardziej independent

  4. iframes, ale prawdopodobnie tak nie jest

 247
Author: Omu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-04 17:40:46

Zalecałbym użycie Html.RenderAction i PartialViewResults, aby to osiągnąć; pozwoli Ci to wyświetlić te same dane, ale każdy widok częściowy nadal będzie miał pojedynczy model widoku i usunie potrzebę BigViewModel

Więc twój widok zawiera coś w stylu:

@Html.RenderAction("Login")
@Html.RenderAction("Register")

Gdzie Login & Register czy obie akcje w kontrolerze są zdefiniowane w następujący sposób:

public PartialViewResult Login( )
{
    return PartialView( "Login", new LoginViewModel() );
}

public PartialViewResult Register( )
{
    return PartialView( "Register", new RegisterViewModel() );
}

The Login & Register będzie wtedy kontrolkami użytkownika znajdującymi się w bieżącym folderze widoku lub w folder udostępniony i chciałby coś takiego:

/Views / Shared / Login.cshtml: (lub / Views / MyView / Login.cshtml)

@model LoginViewModel
@using (Html.BeginForm("Login", "Auth", FormMethod.Post))
{
    @Html.TextBoxFor(model => model.Email)
    @Html.PasswordFor(model => model.Password)
}

/ Views / Shared / Register.cshtml: (lub / Views / MyView / Register.cshtml)

@model ViewModel.RegisterViewModel
@using (Html.BeginForm("Login", "Auth", FormMethod.Post))
{
    @Html.TextBoxFor(model => model.Name)
    @Html.TextBoxFor(model => model.Email)
    @Html.PasswordFor(model => model.Password)
}

I tam masz jedną akcję kontrolera, widok i widok Pliku dla każdej akcji, z każdą całkowicie odrębną i nie zależną od siebie za nic.

 116
Author: TheRightChoyce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-22 21:19:19

Innym sposobem jest użycie:

@model Tuple<LoginViewModel,RegisterViewModel>

Wyjaśniłem, jak używać tej metody zarówno w widoku, jak i w kontrolerze dla innego przykładu: dwa modele w jednym widoku w ASP MVC 3

W Twoim przypadku możesz go zaimplementować używając następującego kodu:

W widoku:

@using YourProjectNamespace.Models;
@model Tuple<LoginViewModel,RegisterViewModel>

@using (Html.BeginForm("Login1", "Auth", FormMethod.Post))
{
        @Html.TextBoxFor(tuple => tuple.Item2.Name, new {@Name="Name"})
        @Html.TextBoxFor(tuple => tuple.Item2.Email, new {@Name="Email"})
        @Html.PasswordFor(tuple => tuple.Item2.Password, new {@Name="Password"})
}

@using (Html.BeginForm("Login2", "Auth", FormMethod.Post))
{
        @Html.TextBoxFor(tuple => tuple.Item1.Email, new {@Name="Email"})
        @Html.PasswordFor(tuple => tuple.Item1.Password, new {@Name="Password"})
}

Zauważ że ręcznie zmieniłem atrybuty nazw dla każdej właściwości podczas budowania formularza. Trzeba to zrobić, w przeciwnym razie nie zostałoby to odpowiednio odwzorowane do metody parametr modelu typu, gdy wartości są wysyłane do powiązanej metody przetwarzania. Sugerowałbym użycie osobnych metod do osobnego przetwarzania tych formularzy, w tym przykładzie użyłem metod Login1 i Login2. Metoda Login1 wymaga posiadania parametru typu RegisterViewModel, a Login2 wymaga parametru typu LoginViewModel.

Jeśli wymagane jest actionlink, możesz użyć:

@Html.ActionLink("Edit", "Edit", new { id=Model.Item1.Id })

W metodzie kontrolera dla widoku należy utworzyć zmienną typu krotka i następnie przeszedł do widoku.

Przykład:

public ActionResult Details()
{
    var tuple = new Tuple<LoginViewModel, RegisterViewModel>(new LoginViewModel(),new RegisterViewModel());
    return View(tuple);
}

Lub można wypełnić dwie instancje LoginViewModel i RegisterViewModel wartościami, a następnie przekazać je do widoku.

 96
Author: Hamid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:17

Użyj modelu widoku, który zawiera wiele modeli widoku:

   namespace MyProject.Web.ViewModels
   {
      public class UserViewModel
      {
          public UserDto User { get; set; }
          public ProductDto Product { get; set; }
          public AddressDto Address { get; set; }
      }
   }

Według ciebie:

  @model MyProject.Web.ViewModels.UserViewModel

  @Html.LabelFor(model => model.User.UserName)
  @Html.LabelFor(model => model.Product.ProductName)
  @Html.LabelFor(model => model.Address.StreetName)
 17
Author: Yini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-04 22:59:01

Czy muszę zrobić inny widok, który zawiera te 2 widoki?

Odpowiedź: Nie

Nie ma innego sposobu jak (bez BigViewModel):

Tak , możesz użyć krotki(przynosi magię w widoku mając wiele modeli).

Kod:

 @model Tuple<LoginViewModel, RegisterViewModel>


    @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
    {
     @Html.TextBoxFor(tuple=> tuple.Item.Name)
     @Html.TextBoxFor(tuple=> tuple.Item.Email)
     @Html.PasswordFor(tuple=> tuple.Item.Password)
    }


    @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
     {
      @Html.TextBoxFor(tuple=> tuple.Item1.Email)
      @Html.PasswordFor(tuple=> tuple.Item1.Password)
     }
 8
Author: VCody,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-28 16:30:56

Dodaj ten ModelCollection.cs do Waszych modeli

using System;
using System.Collections.Generic;

namespace ModelContainer
{
  public class ModelCollection
  {
   private Dictionary<Type, object> models = new Dictionary<Type, object>();

   public void AddModel<T>(T t)
   {
      models.Add(t.GetType(), t);
   }

   public T GetModel<T>()
   {
     return (T)models[typeof(T)];
   }
 }
}

Kontroler:

public class SampleController : Controller
{
  public ActionResult Index()
  {
    var model1 = new Model1();
    var model2 = new Model2();
    var model3 = new Model3();

    // Do something

    var modelCollection = new ModelCollection();
    modelCollection.AddModel(model1);
    modelCollection.AddModel(model2);
    modelCollection.AddModel(model3);
    return View(modelCollection);
  }
}

Widok:

enter code here
@using Models
@model ModelCollection

@{
  ViewBag.Title = "Model1: " + ((Model.GetModel<Model1>()).Name);
}

<h2>Model2: @((Model.GetModel<Model2>()).Number</h2>

@((Model.GetModel<Model3>()).SomeProperty
 3
Author: Morten Frederiksen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-27 07:01:14

Prosty sposób na to

Możemy najpierw wywołać wszystkie modele

@using project.Models

Następnie wyślij swój model z viewbag

// for list
ViewBag.Name = db.YourModel.ToList();

// for one
ViewBag.Name = db.YourModel.Find(id);

I w widoku

// for list
List<YourModel> Name = (List<YourModel>)ViewBag.Name ;

//for one
YourModel Name = (YourModel)ViewBag.Name ;

Następnie łatwo użyć tego modelu

 1
Author: Pnsadeghy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-16 16:44:13

Chcę powiedzieć, że moje rozwiązanie było podobne do odpowiedzi podanej na tej stronie stackoverflow: ASP.NET MVC 4, wiele modeli w jednym widoku?

Jednak w moim przypadku zapytanie linq użyte w kontrolerze nie zadziałało.

To said query:

var viewModels = 
        (from e in db.Engineers
         select new MyViewModel
         {
             Engineer = e,
             Elements = e.Elements,
         })
        .ToList();

W związku z tym "Twoim zdaniem wystarczy określić, że używasz kolekcji modeli widoków" też mi nie wyszło.

Jednak niewielka zmiana tego rozwiązania zadziałała dla mnie. Oto mój rozwiązanie na wypadek, gdyby to komuś pomogło.

Oto mój model widoku, w którym Wiem, że będę miał tylko jeden zespół, ale ten zespół może mieć wiele tablic (i mam folder ViewModels w folderze Moje modele btw, stąd przestrzeń nazw):

namespace TaskBoard.Models.ViewModels
{
    public class TeamBoards
    {
        public Team Team { get; set; }
        public List<Board> Boards { get; set; }
    }
}
To jest mój kontroler. Jest to najbardziej znacząca różnica w stosunku do rozwiązania w linku, o którym mowa powyżej. Buduję Model ViewModel, aby wysłać do widoku inaczej.
public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            TeamBoards teamBoards = new TeamBoards();
            teamBoards.Boards = (from b in db.Boards
                                 where b.TeamId == id
                                 select b).ToList();
            teamBoards.Team = (from t in db.Teams
                               where t.TeamId == id
                               select t).FirstOrDefault();

            if (teamBoards == null)
            {
                return HttpNotFound();
            }
            return View(teamBoards);
        }

W takim razie moim zdaniem nie podaję go jako listy. Ja tylko do " @ model TaskBoard.Modelki.ViewModels.TeamBoards" wtedy potrzebuję tylko dla każdego, gdy iteruję nad tablicami zespołu. Oto mój pogląd:

@model TaskBoard.Models.ViewModels.TeamBoards

@{
    ViewBag.Title = "Details";
}

<h2>Details</h2>

<div>
    <h4>Team</h4>
    <hr />


    @Html.ActionLink("Create New Board", "Create", "Board", new { TeamId = @Model.Team.TeamId}, null)
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => Model.Team.Name)
        </dt>

        <dd>
            @Html.DisplayFor(model => Model.Team.Name)
            <ul>
                @foreach(var board in Model.Boards)
                { 
                    <li>@Html.DisplayFor(model => board.BoardName)</li>
                }
            </ul>
        </dd>

    </dl>
</div>
<p>
    @Html.ActionLink("Edit", "Edit", new { id = Model.Team.TeamId }) |
    @Html.ActionLink("Back to List", "Index")
</p>

Jestem całkiem nowy w ASP.NET MVC więc zajęło mi trochę czasu, żeby to rozgryźć. Mam więc nadzieję, że ten post pomoże komuś zorientować się w projekcie w krótszym czasie. :-)

 1
Author: Notso,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:06
  1. Utwórz jedną nową klasę w swoim modelu i właściwościach LoginViewModel i RegisterViewModel:

    public class UserDefinedModel() 
    {
        property a1 as LoginViewModel 
        property a2 as RegisterViewModel 
    }
    
  2. Następnie użyj UserDefinedModel w Twoim widoku.

 1
Author: Andrew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-16 18:10:47

Możesz zawsze przekazać drugi obiekt w worku widoków lub w widoku danych.

 1
Author: Nada N. Hantouli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-27 12:28:26