뷰에서 여러 모델


302

한 번에 두 가지 모델을 원합니다. 페이지가 모두 포함 LoginViewModel하고 RegisterViewModel.

예 :

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; }
}

이 2 개의 ViewModel을 보유하는 다른 ViewModel을 만들어야합니까?

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

뷰로 가져 오기 위해 유효성 검사 속성이 필요합니다. 이것이 ViewModels가 필요한 이유입니다.

(없이 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)
 }

3
다음을 참조하십시오 : codeproject.com/Articles/687061/…
S.Serpooshan

1
@saeed serpooshan 당신은 코멘트를 게시하고 나에게 도움이 사년 후, 다른 옵션을 사용하여 링크를 너무 많이 주셔서 감사합니다, 난 그냥 사용 ViewBag뷰에서 각과, 훌륭한 작품
shaijut

@stom FYI : 게시물 작성자는 항상 알림을 받지만 다른 사람에게 알리려면 @여기에서 한 것처럼 이름 앞에 표시 해야합니다 .
jpaugh

답변:


260

많은 방법이 있습니다 ...

  1. BigViewModel을 사용하여 다음을 수행하십시오.

    @model BigViewModel    
    @using(Html.BeginForm()) {
        @Html.EditorFor(o => o.LoginViewModel.Email)
        ...
    }
  2. 2 개의 추가보기를 만들 수 있습니다

    Login.cshtml

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

    register.cshtml 같은 것

    생성 후 메인 뷰에서 렌더링하고 뷰 모델 / 뷰 데이터를 전달해야합니다.

    따라서 다음과 같이 될 수 있습니다.

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

    또는

    @{Html.RenderPartial("login", Model.LoginViewModel)}
    @{Html.RenderPartial("register", Model.RegisterViewModel)}
  3. 웹 사이트의 아약스 부분을 사용하면 더 독립적이됩니다.

  4. iframes하지만 아마도 그렇지 않습니다.


2
부분보기를 사용하여 양식에서 두 개의 텍스트 상자 이름이 같은 경우 문제가 있습니까?
Shawn Mclean

2
아니요, firebug (firefox)와 같은 요소를 사용하여 요소 자체를 미세하게 클릭하면 id = "LoginViewModel_Email"name = "LoginViewModel.Email"과 같이 표시되므로 실제로는 고유합니다! 보기 모델은 필요한 것이어야합니다. 각 페이지를 다른 URL에 게시하면됩니다.
Haroon

@Lol 코더 실제로는 각 뷰 모델마다 하나씩 2 개의 형태가되지만 어쨌든 같은 이름을 가진 2 개 또는 3 개 이상의 이름을 가진다면 서버 측에서 해당 이름의 배열을 얻습니다 (매개 변수에 넣으면) 후 조치 방법)
Omu

@Chuck Norris 저는 asp.net mvc 4를 사용하고 partialviewresult 기술을 구현했지만 Expression에서 값을 반환해야@Html.RenderAction 한다는 오류를보고 합니다
Deeptechtons

1
이것이 어떻게 작동하는지 설명 할 수 있습니까? 나는 이것이 문제에 대한 해결책이라는 것을 알고 있지만 그것을 이해할 수는 없다. 이 문제에 대한 비슷한 (약간 다른) 예가 있으며이를 해결하는 방법을 알 수 없습니다.
Andre

127

Html.RenderAction이를 위해 PartialViewResults를 사용하는 것이 좋습니다 . 동일한 데이터를 표시 할 수 있지만 각 부분 뷰에는 여전히 단일 뷰 모델이 있으며BigViewModel

따라서 뷰에는 다음과 같은 내용이 포함됩니다.

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

어디 Login&은 Register다음과 같이 정의 컨트롤러에서 모두 작업입니다 :

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

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

Login&는 Register다음, 또는 공유 폴더에 하나 현재보기 폴더에 존재하는 사용자 컨트롤 것과 같은 것을 좋아하는 것 :

/Views/Shared/Login.cshtml : (또는 /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 : (또는 /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)
}

그리고 각 컨트롤러마다 하나의 컨트롤러 작업,보기 및보기 파일이 있습니다.


4
이것은 디자인 측면에서 많은 의미가 있지만 효율성 측면에서 mvc 사이클의 전체 사이클 3 회를 거쳐야합니까? stackoverflow.com/questions/719027/renderaction-renderpartial/…
Shawn Mclean

6
예, 맞습니다. 각에 대해 추가 전체 MVC주기가 발생합니다 RenderAction. 내 프로젝트에는 항상 기본적으로 dll이 포함되어 있기 때문에 선물 팩의 일부를 항상 잊어 버립니다. 추가 mvc 사이클이 설계 측면에서 제공하는 분리 가치가 있는지에 대한 선호도 및 애플리케이션 요구 사항에 달려 있습니다. 여러 번 RenderAction결과를 캐싱 할 수 있으므로 컨트롤러 팩토리를 통한 약간의 추가 처리 만 수행하면됩니다.
TheRightChoyce

위의 내용을 구현했습니다. 무엇을 놓치고 있습니까? 도와주십시오 : stackoverflow.com/questions/9677818/…
diegohb

이런 세상에! 이것은 문 밖으로 나에게 완벽하게 작동했습니다. 몇 명의 사용자 만있는 내부 사이트를 구축하고 있습니다. 따라서 효율성은 저의 관심사가 아닙니다. 감사합니다!
Derek Evermore

1
PartialView가 작동하도록 중괄호를 사용해야했습니다.
null

113

다른 방법은 다음을 사용하는 것입니다.

@model Tuple<LoginViewModel,RegisterViewModel>

다른 예제를 위해 뷰와 컨트롤러에서이 방법을 사용하는 방법을 설명 했습니다. ASP MVC 3에서 한 뷰에 두 개의 모델

귀하의 경우 다음 코드를 사용하여 구현할 수 있습니다.

보기에서 :

@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"})
}

참고 양식을 구축 할 때 내가 수동으로 이름 변경 즉, 각 속성에 대한 속성. 이 작업을 수행해야합니다. 그렇지 않으면 값이 처리를 위해 관련 메서드로 전송 될 때 모델 형식의 메서드 매개 변수에 제대로 매핑되지 않습니다. 별도의 메소드를 사용하여 이러한 양식을 개별적으로 처리하는 것이 좋습니다.이 예에서는 Login1 및 Login2 메소드를 사용했습니다. Login1 메소드에는 RegisterViewModel 유형의 매개 변수가 필요하고 Login2에는 LoginViewModel 유형의 매개 변수가 필요합니다.

액션 링크가 필요한 경우 다음을 사용할 수 있습니다.

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

보기에 대한 컨트롤러의 메소드에서 Tuple 유형의 변수를 작성한 후보기로 전달해야합니다.

예:

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

또는 LoginViewModel 및 RegisterViewModel의 두 인스턴스를 값으로 채운 후보기로 전달할 수 있습니다.


이것은 그것을 처리하는 좋은 방법이었습니다. 감사합니다! 내가 필요한 걸 했어
Todd Davis

나는 이것을 시도했지만 EditorFor또는 HiddenFor(이상적으로 사용하고 싶은) or 를 사용하면 Login1/ Login2컨트롤러 메소드가 호출 될 때 모델 속성이 설정되지 않습니다 . 아마도 @Name=매핑이 무시되고있을 것입니다. HiddenFor이 상황에 다른 트릭이 필요 합니까 ?
게리 채프먼

1
전혀이하지 않습니다 작업 - 폼이 제출 될 때 당신이 모델에 바인딩 할 수 없습니다

@Hamid Thanks Hamid, MVC의 초보자에게는 이것이 가장 간단한 대답이었습니다. 감사합니다.
Harold_Finch

양식을 제출할 때 모델을 어떻게 바인딩 했습니까?
모하메드 누 렐딘

28

여러 뷰 모델이 포함 된 뷰 모델을 사용하십시오.

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

당신의 관점에서 :

  @model MyProject.Web.ViewModels.UserViewModel

  @Html.LabelFor(model => model.User.UserName)
  @Html.LabelFor(model => model.Product.ProductName)
  @Html.LabelFor(model => model.Address.StreetName)

1
이것은 훌륭한 솔루션이며 모델 검증은 여전히 ​​퀄리티없이 작동합니다. 감사!
AFM-Horizon

11

이 두 가지 견해를 보유하는 다른 견해를 만들어야합니까?

답변 : 아니요

(BigViewModel없이) 다른 방법이 없습니까?

, Tuple을 사용할 수 있습니다 (여러 모델의 관점에서 마술을 가져옵니다).

암호:

 @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)
     }

양식을 수락 한 컨트롤러에 올바르게 매핑되지 않습니까? "name"을 찾기 전에 귀하의 경우 "Item"을 찾을 것이라고 생각했습니다.
SolidSnake4444

7

이 ModelCollection.cs를 모델에 추가

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)];
   }
 }
}

제어 장치:

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);
  }
}

보기:

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

이 접근 방식을 사용하면 서로 다른 모델을 교차하지 않고도 동일한 뷰에서 다른 모델을 사용할 수 있습니다.
Matt Small

6

그렇게하는 간단한 방법

우리는 모든 모델을 먼저 호출 할 수 있습니다

@using project.Models

그런 다음 뷰백으로 모델을 보내십시오.

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

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

그리고보기

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

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

그런 다음 모델처럼 쉽게 사용하십시오.


3

내 조언은 큰보기 모델을 만드는 것입니다.

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

예를 들어 Index.cshtml에서 부분이 2 개인 경우 :

@addTagHelper *,Microsoft.AspNetCore.Mvc.TagHelpers
@model .BigViewModel

@await Html.PartialAsync("_LoginViewPartial", Model.LoginViewModel)

@await Html.PartialAsync("_RegisterViewPartial ", Model.RegisterViewModel )

컨트롤러에서 :

model=new BigViewModel();
model.LoginViewModel=new LoginViewModel();
model.RegisterViewModel=new RegisterViewModel(); 

2

내 솔루션 이이 스택 오버 플로우 페이지에 제공된 답변과 같다고 말하고 싶습니다 : ASP.NET MVC 4, 하나의보기에서 여러 모델?

그러나 제 경우에는 컨트롤러에서 사용한 linq 쿼리가 작동하지 않았습니다.

이것은 쿼리라고합니다 :

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

결과적으로, "보기에서 당신이보기 모델 모음을 사용하고 있음을 지정하십시오"는 나에게도 효과가 없었습니다.

그러나 그 솔루션의 약간의 변형이 저에게 효과적이었습니다. 이것이 누군가를 도울 수있는 경우의 해결책입니다.

여기에 하나의 팀이 있지만 해당 팀에 여러 보드가있을 수 있음을 알 수있는 뷰 모델이 있습니다 (그리고 모델 폴더 btw 내에 네임 스페이스 폴더가 있으므로 네임 스페이스가 있음).

namespace TaskBoard.Models.ViewModels
{
    public class TeamBoards
    {
        public Team Team { get; set; }
        public List<Board> Boards { get; set; }
    }
}

이제 이것은 내 컨트롤러입니다. 이것은 위에서 언급 한 링크의 솔루션과 가장 큰 차이점입니다. 뷰에 다르게 보내도록 ViewModel을 빌드합니다.

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);
        }

그런 다음 내 견해로는 목록으로 지정하지 않습니다. 나는 단지 "@model TaskBoard.Models.ViewModels.TeamBoards"를하고 팀 보드를 반복 할 때 각각에 대해 필요합니다. 여기 내 견해가 있습니다 :

@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>

ASP.NET MVC를 처음 접했기 때문에 이것을 알아내는 데 약간의 시간이 걸렸습니다. 따라서이 게시물이 누군가가 더 짧은 기간 내에 프로젝트를 위해 그것을 파악하는 데 도움이되기를 바랍니다. :-)



1
  1. 하나 개의 새로운 모델의 클래스와 속성 생성 LoginViewModelRegisterViewModel:

    public class UserDefinedModel() 
    {
        property a1 as LoginViewModel 
        property a2 as RegisterViewModel 
    }
  2. 그런 다음 UserDefinedModel귀하의 관점에서 사용 하십시오.


1
예, 그것은 저에게 효과적입니다. 그런 다음 이것을 다음과 같이 참조했습니다. 아래 @notso post를 사용하여 모델 중 하나를 채운 컨트롤러 입력에 사용했던 다른 becuase를 채울 필요가 없습니다
JustJohn

0

IEnumerable을 사용한 간단한 예입니다.

검색 기준 (SearchParams 모델)이있는 양식과 결과에 대한 그리드라는 두 가지 모델을 뷰에서 사용하고 있었고 IEnumerable 모델과 다른 모델을 동일한 뷰에 추가하는 방법에 어려움을 겪었습니다. 여기에 내가 생각해 낸 것이 누군가에게 도움이되기를 바랍니다.

@using DelegatePortal.ViewModels;

@model SearchViewModel

@using (Html.BeginForm("Search", "Delegate", FormMethod.Post))
{

                Employee First Name
                @Html.EditorFor(model => model.SearchParams.FirstName,
new { htmlAttributes = new { @class = "form-control form-control-sm " } })

                <input type="submit" id="getResults" value="SEARCH" class="btn btn-primary btn-lg btn-block" />

}
<br />
    @(Html
        .Grid(Model.Delegates)
        .Build(columns =>
        {
            columns.Add(model => model.Id).Titled("Id").Css("collapse");
            columns.Add(model => model.LastName).Titled("Last Name");
            columns.Add(model => model.FirstName).Titled("First Name");
        })

...)

SearchViewModel.cs :

namespace DelegatePortal.ViewModels
{
    public class SearchViewModel
    {
        public IEnumerable<DelegatePortal.Models.DelegateView> Delegates { get; set; }

        public SearchParamsViewModel SearchParams { get; set; }
....

DelegateController.cs :

// GET: /Delegate/Search
    public ActionResult Search(String firstName)
    {
        SearchViewModel model = new SearchViewModel();
        model.Delegates = db.Set<DelegateView>();
        return View(model);
    }

    // POST: /Delegate/Search
    [HttpPost]
    public ActionResult Search(SearchParamsViewModel searchParams)
    {
        String firstName = searchParams.FirstName;
        SearchViewModel model = new SearchViewModel();

        if (firstName != null)
            model.Delegates = db.Set<DelegateView>().Where(x => x.FirstName == firstName);

        return View(model);
    }

SearchParamsViewModel.cs :

namespace DelegatePortal.ViewModels
{
    public class SearchParamsViewModel
    {
        public string FirstName { get; set; }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.