1

GOAL:

Have a hierarchy of nested elements with unlimited depth.

PROBLEM:

I have a class A, which includes an instance of a class B.

Class B has a list of Comment objects. Each Comment may have a list of "child" Comments.

Therefore, we have a tree-like structure with unlimited-depth nesting (e.g. A.B.Comments[1].Comments[0].Comments[5]....).

Class A Editor View calls:

@Html.EditorFor(m=>m.B)

Class B's Editor Template has (simplified):

<table id="B-comments">
    @for (int i = 0; i < Model.Comment.ToList().Count(); i++)
    {
        @Html.EditorFor(m => m.Comment.ToList()[i])
    }
</table>
<a id="addCommentToB" href="#">Add Comment</a>

And each Editor Template for the Comment class consists of (simplified):

<tr>

   @using (Html.BeginCollectionItem("B.Comment"))
   {
       <td>
           (... STUF ...)    
       </td>

       (...STUF...)

       <td>
           <table class ="commentReplies">
            @for (int i = 0; i < Model.Comment1.ToList().Count(); i++)
            {
                 @Html.EditorFor(m => m.Comment1.ToList()[i])
            }
            </table>
           <a id="addReply" href="#">Add Reply</a>

    </td>
}

The <a ...> links are used to get entry rows via Ajax and append them to the corresponding tables.

When submitting, the binding only works for the first nesting level (A.B.Comments, but not for Comments made on objects in A.B.Comments). The reason, is likely to be due to the @using (Html.BeginCollectionItem("B.Comment")) line, which is generating the indexes only for 1 level of depth.

I'd be very thankful if anyone could give me a suggestion on how to allow unlimited nesting given these circumstances. Is there a way to dynamically modify the argument in Html.BeginCollectionItem(ARG)?

Cheers

EDIT: The simplified ViewModels, as requested

public partial class A
{
    (...)
    public int BID{ get; set; }
    public virtual B B{ get; set; }
    (...)
}

public partial class B
{
    (...)
    public virtual ICollection<Comment> Comment { get; set; }
}

public partial class Comment
{
    (...)
    public Nullable<int> ParentID { get; set; }
    public virtual ICollection<Comment> Comment1 { get; set; }
    public virtual Comment Comment2 { get; set; }
    public virtual B B { get; set; }
    public Nullable<int> BID { get; set; }
}

ADDENDUM:

I ended up creating a different BeginCollectionItem() Html helper that doesn't keep adding prefixes to the generated html's names and id's.

E.g.:

The way I had, if I had a comment inside a comment, the Html helper would generate tags like this: name="*B.Comment[521cfe57-23aa-42d4-9b63-b7fcdd8799c3].*B.Comment.index" My new method just generates name="Entity.Comment.index" which allows the binding to work correctly.

Alberto León gave me the right hint by reminding me that I don't have to actually do an in-depth binding (for instance, bind a comment's comment to its parent and so forth) as capturing the relationship between the comment and the B objects is enough for the binding to work as I wish.

4

2 回答 2

1

您正在以复杂的方式执行此操作。几年前,我设计了 Bside 社交引擎,但遗憾地因为没有发现而死去。

我发现了同样的问题,它有一个非常简单的解决方案。

您需要为每个内容分配一个 guid,并将每个评论假定为一个新内容,因此您始终可以搜索该 guid 内容。然后你只需要创建带有属性 Comments 和方法 Add、Delete、Edit 的接口 ICommentable

然后你需要A类继承ICommentable,你需要编写实现。B也是一样。

然后在业务层中,您从数据库或您的存储方式中获取 A 和 B。并在数据库中搜索 A 和 B 评论。当你得到它时,你需要在评论中搜索评论。

所以在存储方式上,评论总是评论。对与评论相关的内容项没有意义。

关于 ajax 的用户界面,我使用了 jQuery。所以请不要尝试绑定。将每个评论视为独立对象。每个添加按钮添加评论和保存,只能引用评论。您只需将带有新注释的表单发送到 MVC 方法。不要忘记父内容项的 guid(A 类或 B 类或任何评论对象)

于 2013-05-27T16:31:13.030 回答
0

您可以使用 ViewData.TemplateInfo.GetFullHtmlFieldName() 或 ViewData.TemplateInfo.HtmlFieldPrefix 检索当前模型的完整路径

于 2013-05-27T18:28:27.567 回答