Bir görünümde birden çok model


302

Bir görünümde 2 model olmasını istiyorum. Sayfa hem LoginViewModelve öğelerini içerir RegisterViewModel.

Örneğin

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

Bu 2 ViewModeli içeren başka bir ViewModel yapmam gerekir mi?

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

Görünüme getirilmesi için doğrulama niteliklerine ihtiyacım var. Bu yüzden ViewModels'e ihtiyacım var.

Başka bir yol yok mu (olmadan 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)
 }


1
@saeed serpooshan, farklı seçeneklerle bağlantı için çok teşekkür ederim, 4 yıl sonra bir yorum gönderdiniz ve bana yardımcı oldu, sadece ViewBaggörünümde her biri için kullandım , harika çalışıyor
shaijut

@stom Sadece bir FYI: gönderi yazarı her zaman bir bildirim alır, ancak başka birini bilgilendirmek istiyorsanız @, burada yaptığım gibi adlarının önüne koymanız gerekir .
jpaugh

Yanıtlar:


260

Bir çok yol var ...

  1. BigViewModel cihazınızla şunları yapabilirsiniz:

    @model BigViewModel    
    @using(Html.BeginForm()) {
        @Html.EditorFor(o => o.LoginViewModel.Email)
        ...
    }
  2. 2 ek görünüm oluşturabilirsiniz

    Login.cshtml

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

    ve register.cshtml aynı şey

    yaratımdan sonra onları ana görünümde oluşturmalı ve onları viewmodel / viewdata

    böylece şöyle olabilir:

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

    veya

    @{Html.RenderPartial("login", Model.LoginViewModel)}
    @{Html.RenderPartial("register", Model.RegisterViewModel)}
  3. web sitenizin ajax bölümlerini kullanmak daha bağımsız hale gelir

  4. iframes, ama muhtemelen durum böyle değil


2
Kısmi görünümler kullanıldığından, 2 metin kutusunun formda aynı ada sahip olması sorun yaratır mı?
Shawn Mclean

2
Hayır, kundakçı (firefox üzerinde) gibi bir şey kullanarak öğenin üzerine ince tıklamalı ve id = "LoginViewModel_Email" name = "LoginViewModel.Email" gibi bir şey göreceksiniz, bu yüzden gerçekte benzersizler! Bir görünüm modeli ihtiyacınız olan şey olmalı, her sayfayı farklı bir URL'ye gönderin ve iyi olmalısınız
Haroon

@Lol kodlayıcı aslında her bir görünüm modeli için bir tane olmak üzere 2 form olurdu, ancak yine de aynı ada sahip 2 veya 3 veya daha fazlasına sahip olursanız, sunucu tarafında bu ada sahip bir dizi elde edersiniz (eğer parametrelere koyarsanız) sonrası yöntem)
Omu

@Chuck Norris Asp.net mvc 4 kullanıyorum ve partialviewresult tekniğini uyguladım ama İfadenin bir değer döndürmesi gerektiğini@Html.RenderAction bildiren bir hata bildiriyor
Deeptechtons

1
Bunun nasıl çalıştığını açıklayabilir misiniz? Bunun soruna bir çözüm olduğunu anlıyorum, ama herhangi bir anlam ifade edemiyorum. Bu sorunun benzer (biraz farklı) bir örneğim var ve nasıl çözüleceğini anlayamıyorum.
Andre

127

Bunu Html.RenderActiongerçekleştirmek için ve PartialViewResults kullanarak tavsiye ederim ; aynı verileri görüntülemenize izin verir, ancak her kısmi görünüm yine de tek bir görünüm modeline sahip olur ve birBigViewModel

Dolayısıyla, görüşünüz aşağıdaki gibi bir şey içeriyor:

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

Nerede Loginve Registeraşağıdaki gibi tanımlanır kontrolörünüze hem işlemler şunlardır:

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

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

Login& RegisterSonra veya Paylaşılan klasöründe ya Geçerli Görünüm klasöründe bulunan kullanıcı kontrolleri olacağını ve böyle bir şey istiyorum:

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

Ve orada tek bir denetleyici eylem var, her eylem için dosya tamamen her biri farklı ve herhangi bir şey için birbirine bağlı değil görüntüleme ve görüntüleme.


4
Bu, tasarım açısından bir anlam ifade ediyor, ancak verimlilik açısından, mvc döngüsünün 3 tam döngüsüne girmek zorunda değil mi? stackoverflow.com/questions/719027/renderaction-renderpartial/…
Shawn Mclean

6
Evet haklısınız: her biri için ek bir tam MVC döngüsüne neden olur RenderAction. Projem her zaman varsayılan olarak bu dll'yi içerdiğinden her zaman vadeli işlem paketinin bir kısmını unutuyorum. Ek mvc döngülerinin tasarım tarafında verdiği ayrılığa değip değmeyeceği konusunda gerçekten tercih ve uygulama gereklilikleri. Çoğu zaman RenderActionsonuçları önbelleğe alabilirsiniz, böylece aldığınız tek hit kontrolör fabrikası üzerinden hafif ekstra işlemdir.
TheRightChoyce

Yukarıdakileri uyguladım .. ne eksik? Lütfen yardım: stackoverflow.com/questions/9677818/…
diegohb

Kahretsin! Bu benim için mükemmel çalıştı. Sadece birkaç kullanıcıyla dahili bir site inşa ediyorum ... bu yüzden verimlilik benim için gerçek bir endişe değil. TEŞEKKÜR EDERİM!
Derek Evermore

1
PartialView çalışmak için kıvırcık parantez kullanmak zorunda kaldı.
null

113

Başka bir yol da kullanmaktır:

@model Tuple<LoginViewModel,RegisterViewModel>

Başka bir örnek için hem görünümde hem de denetleyicide bu yöntemin nasıl kullanılacağını açıkladım: ASP MVC 3'te bir görünümde iki model

Sizin durumunuzda aşağıdaki kodu kullanarak uygulayabilirsiniz:

Görünümde:

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

Formu oluştururken her özellik için Ad özniteliklerini el ile değiştirdiğimi unutmayın . Bunun yapılması gerekir, aksi takdirde değerler işlenmek üzere ilgili yönteme gönderildiğinde yöntemin tip modeli parametresiyle düzgün eşleştirilmez. Bu formları ayrı ayrı işlemek için ayrı yöntemler kullanmanızı öneririm, bu örnek için Login1 ve Login2 yöntemlerini kullandım. Login1 yöntemi, RegisterViewModel türünde bir parametrenin olmasını gerektirir ve Login2, LoginViewModel türünde bir parametre gerektirir.

bir eylem bağlantısı gerekiyorsa şunları kullanabilirsiniz:

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

denetleyicinin görünüm yönteminde, Tuple türünde bir değişkenin oluşturulması ve daha sonra görünüme geçirilmesi gerekir.

Misal:

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

veya iki LoginViewModel ve RegisterViewModel örneğini değerlerle doldurabilir ve sonra görünüme aktarabilirsiniz.


Bu üstesinden gelmek için harika bir yoldu, teşekkürler! İhtiyacım olanı yaptım.
Todd Davis

Bunu denedim ama / EditorForveya HiddenFor(ideal olarak kullanmak istediğim şey) kullanırsam, Login1/ Login2controller yöntemleri çağrıldığında model özellikleri ayarlanmaz . Muhtemelen @Name=haritalama yok sayılıyor. Does HiddenForbu durum için başka hile gerektiren?
Gary Chapman

1
Bu hiç işe yaramaz - form gönderildiğinde modele bağlanamazsınız

@Hamid Teşekkürler Hamid, MVC'deki bir acemi için bu benim için en basit cevaptı. Teşekkür ederim.
Harold_Finch

Formu gönderirken Modeli nasıl bağladınız?
Mohammed Noureldin

28

Birden çok görünüm modeli içeren bir görünüm modeli kullanın:

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

Sizce:

  @model MyProject.Web.ViewModels.UserViewModel

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

1
Bu harika bir çözüm ve model doğrulaması hala hiçbir kalite olmadan çalışıyor. Teşekkürler!
AFM-Horizon

11

Bu 2 görünümü içeren başka bir görünüm oluşturmam gerekir mi?

Cevap: Hayır

(BigViewModel olmadan) gibi başka bir yol yok mu:

Evet , Tuple'i kullanabilirsiniz (çoklu modele sahip görünümde sihir getirir).

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

Bu, formu kabul eden denetleyiciyle düzgün eşleşmez mi? Ben "isim" aramadan önce senin durumda "Öğe" arayacağını düşündüm.
SolidSnake4444

7

Bu ModelCollection.cs dosyasını Modellerinize ekleyin

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

Denetleyici:

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

Görünüm:

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

Bu yaklaşımı beğendim çünkü farklı modelleri kesiştirmeden aynı görünümde kullanmama izin veriyor.
Matt Small

6

bunu yapmanın basit bir yolu

önce tüm modeli çağırabiliriz

@using project.Models

sonra modelinizi viewbag ile gönderin

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

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

ve görüşte

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

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

o zaman bunu kolayca Model gibi kullanın


3

Benim tavsiyem büyük görüş modeli yapmak:

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

Index.cshtml dosyanızda, örneğin 2 bölümünüz varsa:

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

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

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

ve denetleyicide:

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

2

Benim çözüm bu stackoverflow sayfasında sağlanan cevap gibi olduğunu söylemek istiyorum: ASP.NET MVC 4, bir görünümde birden çok model?

Ancak, benim durumumda, Kontrolörlerinde kullandıkları linq sorgusu benim için çalışmadı.

Bu sorgu:

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

Sonuç olarak, "sizin görüşünüze göre sadece bir görünüm modelleri koleksiyonu kullandığınızı belirtin" benim için de işe yaramadı.

Ancak, bu çözüm üzerinde küçük bir değişiklik benim için işe yaradı. İşte bu herkesin yardım etmesi için benim çözümüm.

İşte benim sadece bir ekibim olacağını biliyorum benim görünüm modeli ama bu ekibin birden fazla panoları (ve benim Modeller klasöründe btw, dolayısıyla ad alanı içinde bir ViewModels klasörü var):

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

Şimdi bu benim denetleyicim. Bu, yukarıda atıfta bulunulan bağlantıdaki çözümden en önemli farktır. Ben görünüme farklı göndermek için ViewModel inşa.

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

Sonra bence bunu bir liste olarak belirtmiyorum. Ben sadece "model TaskBoard.Models.ViewModels.TeamBoards" yapmak Sonra sadece Takım panoları üzerinde yineleme zaman her biri için bir ihtiyacım var. İşte benim görüşüm:

@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 için oldukça yeniyim, bu yüzden bunu anlamak biraz zaman aldı. Umarım bu yazı birisinin projesinde daha kısa bir zaman diliminde çözmesine yardımcı olur. :-)



1
  1. Yeni bir Modelinizdeki sınıf ve özelliklerini oluşturun LoginViewModelve RegisterViewModel:

    public class UserDefinedModel() 
    {
        property a1 as LoginViewModel 
        property a2 as RegisterViewModel 
    }
  2. Ardından UserDefinedModelgörünümünüzde kullanın .


1
evet, bu benim için işe yarıyor. daha sonra bu şekilde referans verdim: (model görünümün en üstünde ilan edildi. İçinde 2 model vardı: profil ve emailstuff..... @ Html.DisplayNameFor (model => model.profile.BlackoutBegin) denetleyici Aşağıdaki @notso post kullanarak modellerden birini doldurdum.Bir giriş için kullandığım diğer doldurmak zorunda değildi
JustJohn

0

Bu, IEnumerable ile basitleştirilmiş bir örnektir.

Görünümde iki model kullanıyordum: arama ölçütlerine sahip bir form (SearchParams modeli) ve sonuçlar için bir ızgara ve aynı görünüme IEnumerable modelinin ve diğer modelin nasıl ekleneceği ile uğraştım. İşte geldim, umarım bu birine yardımcı olur:

@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; }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.