각 모델에 중첩된 MVC 레이저 뷰
일반적인 시나리오를 상상해 보세요. 이것은 제가 발견한 것의 더 간단한 버전입니다.사실 제 집에는 몇 겹의 둥지가 더 있습니다.
하지만 이것이 시나리오입니다.
테마 포함 목록 카테고리 포함 목록 제품 포함 목록 포함
내 컨트롤러는 해당 테마에 대한 모든 카테고리, 이 카테고리 내의 제품 및 해당 주문과 함께 완전하게 채워진 테마를 제공합니다.
주문 컬렉션에는 편집할 수 있어야 하는 수량이라는 속성이 있습니다.
@model ViewModels.MyViewModels.Theme
@Html.LabelFor(Model.Theme.name)
@foreach (var category in Model.Theme)
{
@Html.LabelFor(category.name)
@foreach(var product in theme.Products)
{
@Html.LabelFor(product.name)
@foreach(var order in product.Orders)
{
@Html.TextBoxFor(order.Quantity)
@Html.TextAreaFor(order.Note)
@Html.EditorFor(order.DateRequestedDeliveryFor)
}
}
}
대신 람다를 사용하면 각 루프에 대한 "테마"가 아닌 상단 모델 개체에 대한 참조만 표시됩니다.
제가 거기서 하려고 하는 것이 가능한 것일까요, 아니면 제가 가능한 것을 과대평가했거나 오해한 것일까요?
위와 같은 경우 텍스트 상자에 오류가 표시됩니다.
CS0411: 메서드 'System'의 형식 인수입니다.웹.MVC.Html.InputExtensions.텍스트 상자(시스템).웹.MVC.Html 도우미, 시스템.Linq.표현식.식 >)"는 사용법으로 유추할 수 없습니다.형식 인수를 명시적으로 지정해 보십시오.
감사해요.
간단한 대답은 다음과 같습니다.for()
의 신루프사니다 를 하세요.foreach()
루프. 다음과 같은 것들.
@for(var themeIndex = 0; themeIndex < Model.Theme.Count(); themeIndex++)
{
@Html.LabelFor(model => model.Theme[themeIndex])
@for(var productIndex=0; productIndex < Model.Theme[themeIndex].Products.Count(); productIndex++)
{
@Html.LabelFor(model=>model.Theme[themeIndex].Products[productIndex].name)
@for(var orderIndex=0; orderIndex < Model.Theme[themeIndex].Products[productIndex].Orders; orderIndex++)
{
@Html.TextBoxFor(model => model.Theme[themeIndex].Products[productIndex].Orders[orderIndex].Quantity)
@Html.TextAreaFor(model => model.Theme[themeIndex].Products[productIndex].Orders[orderIndex].Note)
@Html.EditorFor(model => model.Theme[themeIndex].Products[productIndex].Orders[orderIndex].DateRequestedDeliveryFor)
}
}
}
하지만 이것은 왜 이것이 문제를 해결하는지를 설명합니다.
이 문제를 해결하기 전에 최소한 세 가지 사항을 이해해야 합니다.제가 이 틀을 가지고 일을 시작했을 때 이것을 오랫동안 화물 재배했다는 것을 인정해야 합니다.그리고 저는 무슨 일이 일어나고 있는지 알아내는 데 꽤 오랜 시간이 걸렸습니다.
이 세 가지는 다음과 같습니다.
- 어떻게 하십니까?
LabelFor
타기...For
MVC에서 일하는 도우미? - 표현식 트리란?
- 모델 바인더는 어떻게 작동합니까?
이 세 가지 개념은 모두 함께 연결되어 답을 얻습니다.
어떻게 하십니까?LabelFor
타기...For
MVC에서 일하는 도우미?
그래서, 당신은 그것을 사용했습니다.HtmlHelper<T>
의확자장의 내선 입니다.LabelFor
그리고.TextBoxFor
그리고 다른 것들을 호출할 때 람다를 전달하면 마법처럼 html이 생성됩니다.하지만 어떻게요?
그래서 가장 먼저 주목해야 할 것은 이 도우미들의 서명입니다.다음에 대한 가장 간단한 오버로드를 살펴보겠습니다.TextBoxFor
public static MvcHtmlString TextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression
)
의 첫째, ▁extension의 입니다.HtmlHelper
<TModel>
간단히 설명하자면, 레이저가 이 뷰를 렌더링하면 클래스가 생성됩니다.에는 이스클의다인내니다입스스턴음의의 .HtmlHelper<TModel>
으로서).Html
그래서 당신이 사용할 수 있는 것입니다.@Html...
서), 위치TModel
는 에정유니다에 입니다.@model
진술. 여러분 이 을 보고 때 당서이당신, 신이보볼때우.TModel
항상 그런 유형일 것입니다.ViewModels.MyViewModels.Theme
.
자, 다음 주장은 좀 까다롭습니다.이제 호출 내용을 살펴보겠습니다.
@Html.TextBoxFor(model=>model.SomeProperty);
우리는 작은 람다를 가지고 있는 것처럼 보입니다. 그리고 만약 누군가가 그 서명을 추측한다면, 사람들은 이 주장의 유형이 단순히Func<TModel, TProperty>
서, 디에어TModel
는 뷰 이며 뷰모유 다니입형의입니다.TProperty
속성 유형으로 유추됩니다.
하지만 그것은 완전히 옳지 않습니다, 만약 당신이 실제 논쟁의 유형을 본다면.Expression<Func<TModel, TProperty>>
.
따라서 일반적으로 람다를 생성할 때 컴파일러는 다른 함수와 마찬가지로 람다를 가져와 MSIL로 컴파일합니다(이것이 대리인, 메소드 그룹 및 람다가 코드 참조일 뿐이기 때문에 어느 정도 호환성 있게 사용할 수 있는 이유입니다).
가 그 가 나컴그가유러형인 것을 때Expression<>
람다를 MSIL로 즉시 컴파일하지 않고 식 트리를 생성합니다!
표현식 트리란?
그래서, 표현 트리는 도대체 무엇입니까?뭐, 복잡하지도 않고 공원 산책도 아닙니다.견적서 작성하기:
식 트리는 트리와 같은 데이터 구조의 코드를 나타냅니다. 여기서 각 노드는 식(예: 메서드 호출 또는 x < y와 같은 이진 연산)입니다.
간단히 말해서, 표현식 트리는 "동작"의 집합으로서의 함수의 표현입니다.
의 model=>model.SomeProperty
는 " Property를 가져오십시오라는.
이 표현식 트리는 호출할 수 있는 함수로 컴파일할 수 있지만 표현식 트리인 한 노드의 집합일 뿐입니다.
그럼 그게 무슨 소용이겠어요?
그렇게Func<>
또는Action<>
일단 당신이 그것들을 가지면, 그것들은 거의 원자력입니다.할 수 있는 은 당이정할로수있것은는신말것은▁all▁you입니다.Invoke()
그들, 일명 그들에게 그들이 해야 할 일을 하라고 말합니다.
Expression<Func<>>
반면에 추가, 조작, 방문 또는 컴파일 및 호출할 수 있는 작업 모음을 나타냅니다.
그런데 왜 나한테 이 모든 걸 말하는 거예요?
그래서 그것에 대한 이해와 함께.Expression<>
즉, 우리는 돌아갈 수 있습니다.Html.TextBoxFor
텍스트 상자를 렌더링할 때는 제공하는 속성에 대한 몇 가지 정보를 생성해야 합니다.같은 것들attributes
검증을 위해 부동산에, 특히 이 경우에는 무엇을 명명할지 결정해야 합니다.<input>
꼬리표를 달다
표현 트리를 "걸어서" 이름을 짓는 것으로 이를 수행합니다. 그서다음같은표현로으과래로ion▁like와 같은 은.model=>model.SomeProperty
사용자가 요청하는 속성을 수집하고 구축하는 식을 사용합니다.<input name='SomeProperty'>
.
더 , 예를 들면 들면자예들면, 예를복를한잡,model=>model.Foo.Bar.Baz.FooBar
생성될 수 있습니다.<input name="Foo.Bar.Baz.FooBar" value="[whatever FooBar is]" />
돼요?그것은 단지 일이 아닙니다.Func<>
네, 하지만 그것이 어떻게 일을 하는지는 여기서 중요합니다.
(LINQ to SQL과 같은 다른 프레임워크는 식 트리를 걷고 다른 문법(이 경우 SQL 쿼리)을 구축하여 유사한 작업을 수행합니다.)
모델 바인더는 어떻게 작동합니까?
그러면 모델 바인더에 대해 간략하게 설명해야 합니다.양식이 게시되면 플랫과 같습니다.Dictionary<string, string>
중첩된 보기 모델이 가질 수 있는 계층 구조를 잃었습니다.이 키-값 쌍 조합을 사용하여 일부 속성을 가진 개체를 다시 수화하는 것이 모델 바인더의 작업입니다.어떻게 하는 거지?당신은 게시된 입력의 "키" 또는 이름을 사용하여 그것을 추측했습니다.
양식 게시물이 다음과 같은 경우
Foo.Bar.Baz.FooBar = Hello
은 그고당신모글있올습다니리고을델라는 모델에 글을 올리고 있습니다.SomeViewModel
그런 다음 도우미가 처음에 했던 것과 반대로 합니다.그것은 "Foo"라는 부동산을 찾습니다.그리고는 "Foo"의 "Bar"라는 속성을 찾고, "Baz"라는 속성을 찾습니다. 그리고...
마지막으로 값을 "FooBar" 유형으로 구문 분석하여 "FooBar"에 할당하려고 합니다.
휴!!!
그리고 voila, 당신은 당신의 모델을 가지고 있습니다.방금 작성된 모델 바인더는 요청된 수행으로 전달됩니다.
하지 않는 는 솔션이않이 때문입니다.Html.[Type]For()
도우미들은 표현이 필요합니다.그리고 당신은 그들에게 가치를 주고 있습니다.그것은 그 가치에 대한 맥락이 무엇인지 전혀 알지 못합니다. 그리고 그것으로 무엇을 해야 할지도 모릅니다.
어떤 사람들은 부분을 사용해서 렌더링할 것을 제안했습니다.이론적으로는 이것이 효과가 있겠지만, 아마도 여러분이 기대하는 방식은 아닐 것입니다.부을렌할때다유변형다경니합의 종류를 입니다.TModel
사용자가 다른 뷰 컨텍스트에 있기 때문입니다.이 더 짧은할 수 합니다.또한 도우미가 사용자의 표현식 이름을 생성할 때 표현식 이름이 얕아진다는 의미도 있습니다.전체 컨텍스트가 아닌 지정된 식을 기반으로 생성됩니다.
이제 "Baz"를 렌더링한 부분이 있다고 가정해 보겠습니다(이전의 예에서).그 부분 안에서 당신은 그냥 이렇게 말할 수 있습니다.
@Html.TextBoxFor(model=>model.FooBar)
보다는
@Html.TextBoxFor(model=>model.Foo.Bar.Baz.FooBar)
즉, 다음과 같은 입력 태그가 생성됩니다.
<input name="FooBar" />
Model을 에는 즉, 이, 양, 된View Model, 이, 모은다라는 .FooBar
이닌에서 TModel
기껏해야 거기에 없고, 최악의 경우에는 완전히 다른 것입니다.만약 당신이 수락하는 특정한 행동에 게시하고 있었다면.Baz
루트 모델보다는, 이것이 잘 작동할 것입니다!사실 부분은 보기 컨텍스트를 변경하는 좋은 방법입니다. 예를 들어, 모든 양식이 다른 작업에 게시되는 여러 개의 양식이 있는 페이지가 있는 경우 각 작업에 부분을 렌더링하는 것이 좋습니다.
, 은 이제이모것얻으면을, 러은정흥일시수있다습니작할들을운미로말여분든▁interest▁with다▁로 정말 흥미로운 일들을 시작할 수 있습니다.Expression<>
프로그램적으로 확장하고 그들과 함께 다른 깔끔한 일들을 함으로써.저는 그 어떤 것도 관여하지 않을 것입니다.하지만, 바라건대, 이것이 여러분에게 배후에서 무슨 일이 일어나고 있는지 그리고 왜 일들이 있는 그대로 행동하는지에 대해 더 잘 이해할 수 있게 해줄 것입니다.
EditorTemplates를 사용하면 컨트롤러의 보기 폴더에 "EditorTemplates"라는 디렉토리를 만들고 중첩된 각 엔터티(엔티티 클래스 이름)에 대해 별도의 보기를 배치할 수 있습니다.
기본 보기:
@model ViewModels.MyViewModels.Theme
@Html.LabelFor(Model.Theme.name)
@Html.EditorFor(Model.Theme.Categories)
카테고리 보기(/MyController/EditorTemplates/Category.cshtml):
@model ViewModels.MyViewModels.Category
@Html.LabelFor(Model.Name)
@Html.EditorFor(Model.Products)
제품 보기(/MyController/EditorTemplates/Product.cshtml):
@model ViewModels.MyViewModels.Product
@Html.LabelFor(Model.Name)
@Html.EditorFor(Model.Orders)
등등
이쪽 html.EditorForhelper는 순서대로 요소 이름을 생성하므로 게시된 테마 엔티티 전체를 검색하는 데 더 이상 문제가 없습니다.
범주 부분 및 제품 부분을 추가할 수 있습니다. 각 범주는 기본 모델의 작은 부분을 자체 모델로 사용합니다. 즉, 범주의 모델 유형이 IE 번호일 수 있으므로 모델에 전달할 수 있습니다.주제가.제품의 일부는 모델을 통과하는 IE 번호일 수 있습니다.(카테고리 부분 내에서) 제품.
그렇게 하는 것이 앞으로 나아가는 올바른 방법인지는 잘 모르겠지만, 알고 싶습니다.
편집
이 답변을 게시한 이후로 편집기 템플릿을 사용하여 반복 입력 그룹 또는 항목을 가장 쉽게 처리할 수 있는 방법을 찾았습니다.모든 유효성 검사 메시지 문제를 처리하고 제출/모델 바인딩 문제를 자동으로 형성합니다.
바인딩된 모델에 대해 뷰 내의 각 루프에 사용하는 경우...당신의 모델은 목록 형식이어야 합니다.
예
@model IEnumerable<ViewModels.MyViewModels>
@{
if (Model.Count() > 0)
{
@Html.DisplayFor(modelItem => Model.Theme.FirstOrDefault().name)
@foreach (var theme in Model.Theme)
{
@Html.DisplayFor(modelItem => theme.name)
@foreach(var product in theme.Products)
{
@Html.DisplayFor(modelItem => product.name)
@foreach(var order in product.Orders)
{
@Html.TextBoxFor(modelItem => order.Quantity)
@Html.TextAreaFor(modelItem => order.Note)
@Html.EditorFor(modelItem => order.DateRequestedDeliveryFor)
}
}
}
}else{
<span>No Theam avaiable</span>
}
}
그것은 오류에서 분명합니다.
"For"가 추가된 Html 도우미에는 람다 식을 매개 변수로 사용해야 합니다.
값을 직접 전달하는 경우에는 일반 값을 사용하는 것이 좋습니다.
예.
TextboxFor(...) 대신 Textbox()
TextboxFor의 구문은 Html과 같습니다.TextBoxFor(m=>m).속성)
시나리오에서 사용할 인덱스를 제공하므로 루프에 기본을 사용할 수 있습니다.
@for(int i=0;i<Model.Theme.Count;i++)
{
@Html.LabelFor(m=>m.Theme[i].name)
@for(int j=0;j<Model.Theme[i].Products.Count;j++) )
{
@Html.LabelFor(m=>m.Theme[i].Products[j].name)
@for(int k=0;k<Model.Theme[i].Products[j].Orders.Count;k++)
{
@Html.TextBoxFor(m=>Model.Theme[i].Products[j].Orders[k].Quantity)
@Html.TextAreaFor(m=>Model.Theme[i].Products[j].Orders[k].Note)
@Html.EditorFor(m=>Model.Theme[i].Products[j].Orders[k].DateRequestedDeliveryFor)
}
}
}
훨씬 간단한 또 다른 가능성은 속성 이름 중 하나가 잘못되었을 수 있습니다(아마 클래스에서 방금 변경한 이름일 수 있습니다).이것이 레이저페이지에서 저를 위한 것이었습니다.NET 코어 3.
언급URL : https://stackoverflow.com/questions/8894442/mvc-razor-view-nested-foreachs-model
'programing' 카테고리의 다른 글
Azure DevOps에서 파일의 원시 콘텐츠에 대한 링크를 가질 수 있습니까? (0) | 2023.05.03 |
---|---|
디렉토리의 모든 파일 이름을 $filename_h에서 $filename_half로 변경하시겠습니까? (0) | 2023.05.03 |
"ExtensionlessUrlHandler-Integrated-4.0" 처리기의 모듈 목록에 잘못된 모듈 "ManagedPipelineHandler"가 있음 (0) | 2023.05.03 |
잠시 후의 휴식...웬드루프 (0) | 2023.05.03 |
Mongoose에서 Model.findOne()과 Model.findById()의 차이점은 무엇입니까? (0) | 2023.05.03 |