我已经把头发撕掉了,所以我正在寻求帮助。我构建了一个简短的递归HTML Helper来显示列表列表。我想将任何编辑返回给控制器。一个孩子的孩子不断回来。当我删除递归并强制通过“for循环”的第二层时,它似乎工作。任何线索?我准备放弃RAZOR,只是学会在Jquery做这一切......
根据我的代码,当模型被回发时,问题就出在这里(你会在后期ActionResult方法的评论中看到这一点):
Node.Name没问题
Node.Children [0] .Name没问题
Node.Children [1] .Name是好的
Node.Children [1] .Children = null(这就是问题所在!)
控制器代码
public ActionResult Y()
{
Node driverTree = new Node() { Name="Level1", Children = new List<Node>() };
driverTree.Children.Add(new Node() { Children = null, Name = "Level2A" });
driverTree.Children.Add(new Node() {Name ="Level2B", Children = new List<Node> {new Node{Name="Level3A", Children=null},
new Node{Name="Level3B", Children=null}}
});
return View(driverTree);
}
[HttpPost]
public ActionResult Y(Node Node)
{
//Keeps returning:
// Node.Name is ok
// Node.Children[0].Name is ok
// Node.Children[1].Name is ok
// Node.Children[1].Children = null (HERE LIES THE PROBLEM!)
int x = 5; //
return View();
}
}
public class Node
{
public string Name { get; set; }
public List<Node> Children { get; set; }
public bool IsChecked { get; set; }
}
查看代码
@model JqueryUITests.Controllers.Node
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script src="../../Scripts/jquery-ui-1.10.3.min.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-ui.unobtrusive-2.1.0.min.js" type="text/javascript"></script>
}
@helper ShowTree(List<JqueryUITests.Controllers.Node> children)
{
<ul>
@for (int i = 0; i < children.Count;i++ )
{
<li>
@Html.EditorFor(x => children[i].Name)
@if (children[i].Children != null)
{
@ShowTree(children[i].Children)
}
</li>
}
</ul>
}
@using (Html.BeginForm())
{
<ul id="tree">
<li>
@Html.EditorFor(x=>Model.Name)
@ShowTree(Model.Children)
</li>
</ul>
<p>
<input type="submit" value="Create" />
</p>
}
HTML CODE
<form action="/X/Y" method="post"> <ul id="tree">
<li>
<input class="text-box single-line" id="Name" name="Name" type="text" value="Level1" />
<ul>
<li>
<input class="text-box single-line" id="children_0__Name" name="children[0].Name" type="text" value="Level2A" />
</li>
<li>
<input class="text-box single-line" id="children_1__Name" name="children[1].Name" type="text" value="Level2B" />
<ul>
<li>
<input class="text-box single-line" id="children_0__Name" name="children[0].Name" type="text" value="Level3A" />
</li>
<li>
<input class="text-box single-line" id="children_1__Name" name="children[1].Name" type="text" value="Level3B" />
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>
<input type="submit" value="Create" />
</p>
答案 0 :(得分:2)
列表正在为每个节点呈现一个项目,但它没有正确呈现每个节点的名称属性。
当回传输入并重新创建模型时,Razor使用name属性处理列表以创建数组。例如
List<Foo> AllMyFoos { new Foo { Id = 1 }, new Foo { Id = 2 }, new Foo { Id = 3 }}
将会像这样呈现(按照上面的例子):
<input type="text" name="AllMyFoos[0].Id" />
<input type="text" name="AllMyFoos[1].Id" />
<input type="text" name="AllMyFoos[2].Id" />
在幕后,Razor和MVC中的模型绑定然后重新创建Foo对象列表并将其传递给您的控制器方法。
递归方法的问题在于,当您使用子节点列表调用它时,正在呈现每个子节点的索引,并且您正在丢失将其定义为另一个节点的子节点的信息。
这有意义吗?
看看这个问题并阅读有关收藏类型的显示模板的答案 - 这是实现你所追求的目标的更好方法。
答案 1 :(得分:1)
问题很明显:
@Html.EditorFor(x => children[i].Name)
通常x
表示模型,然后属性格式为x.children[i].Name
。下一级将是x.children [i] .children [j] .Name。 EditorFor
从该表达式派生<input />
字段的id和名称。在你的情况下,表达式总是children[i].Name
,因此它会破坏id / name相对于你的根Model
的映射。
我不确定是否有一种很好的方法可以像你想要的那样进行递归渲染。也许使用非lambda版本Html.Editor(string expression)
,您可以将表达式构造为字符串,并在代码中处理嵌套级别(例如:@Html.Editor("Children[1].Children[2].Name")
)。
您有责任生成正确的值"Children[1].Children[2].Name"
。
答案 2 :(得分:0)
扩展dav83关于显示模板的评论。看起来应该是这样的。
文件
视图\ DisplayTemplates \ Node.cshtml
@model JqueryUITests.Controllers.Node
<li>
@Html.EditorFor(x => x.Name)
@if (Model.Children != null)
{
<ul>
@Html.Editor(x => x.Children)
</ul>
}
</li>
现在在你看来。
@model JqueryUITests.Controllers.Node
@section Scripts
{
@Scripts.Render("~/bundles/jqueryval")
<script src="../../Scripts/jquery-ui-1.10.3.min.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-ui.unobtrusive-2.1.0.min.js" type="text/javascript"></script>
}
@using (Html.BeginForm())
{
<ul id="tree">
@Html.EditorForModel()
</ul>
<p>
<input type="submit" value="Create" />
</p>
}
MVC将使用您的模型的Node DisplayTemplate呈现HTML。此外,当您调用@Html.EditorFor(x => x.Children)
时,它将使用显示模板呈现集合中的每个项目。这是您获得构建整个树的递归的地方。
此外,它将跟踪它在树中的位置并正确命名HTML元素,允许您的树按照您的预期发布。