MVC ViewModel绑定构造与展平 [英] MVC ViewModel Binding Construction vs. Flattening

查看:82
本文介绍了MVC ViewModel绑定构造与展平的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的ViewModel(同样在我的Domain模型中)中,我有一种动态的Property结构,其中Profile元素是基类ProfileVM的列表,并引用ProfileDefinitionElement(只是为了解释ViewModel而未粘贴完整内容) ).

In my ViewModel (also in my Domain model), I have kinda dynamic Property Structure where the Profile Elements are a List of the base class ProfileVM and refer to a ProfileDefinitionElement (just to explain the ViewModel without pasting the full thing).

    public class OwnProfileVM
{
    public OwnProfileVM() {}
    public ProfileDefinitionVM ProfileDefinitionVM { get; set; }
    public ProfileVM ProfileVM { get; set; }
}

所以我使用Linq Single语句绑定我的属性:

So I bind my Properties using a Linq Single statement:

 @Model.ProfileDefinitionVM.ProfileElementDefinitions.Single(p => p.Key == ProfileElementKey.CompanyName.ToString()).Title

这适用于显示数据.但是当这样发回邮件时:

This works for showing data. But when posting back like this:

@Html.TextBoxFor(model => ((ProfileElementTextVM)model.ProfileVM.ProfileElements
            .Single(p=> p.ProfileElementDefinition.Key == ProfileElementKey.CompanyName.ToString()))
            .Text

.. model属性为null. 这是因为无参数构造函数在没有填充任何属性的情况下构建了OwnProfileVM对象.

..the model properties are null. This is because of the parameterless constructor which builds the OwnProfileVM object without any properties filled in.

经过研究,我发现有两种解决方法:

After some research I found out that there are two ways to solve this:

  1. 平铺" ViewModel.因此,我将为每个配置文件元素具有固定的属性.这可以工作,但是缺点是我无法使用Automapper映射数据.我将不得不手动"将ViewModel填充到模型.这将导致Controller中的代码更多,并且更大"但更简单的ViewModel.在本文
  2. 中看到
  3. 找到一种方法,将定义数据传递到ViewModel构造方法中,以在回发之前构建属性列表.
  1. "Flatten" the ViewModel. So I would have a fixed Property for every Profile Element. This would work, but the disadvantage would be that I couldn't map the data with the Automapper. I would have to fill the ViewModel to the Model "manually". This would result in more Code in the Controller and a "bigger", but simpler ViewModel. Seen in this article
  2. Find a way to pass the Definition data into the ViewModel Constructor to build the list of Properties before posting back.

现在我的问题:

  1. 第二种方法是否可能?如果可以,这将如何进行?我还没有找到一种方法.
  2. 如果第一个问题的回答为是",那么您会选择哪种方式?

推荐答案

看起来很复杂.最好将其简化一下.

Looks complicated. It may be best to simplify it a bit.

根据我的经验,控制器中的模型属性为null,因为绑定器无法理解如何将表单元素名称与关联的属性链接.例如,我已经在使用foreach的列表中看到了它:

In my experience, model properties are null in the controller because the binder cannot understand how to link the form element name with the associated property. For example, I've seen it with lists where foreach has been used:

(model has a) List<Something> Somethings.....

foreach (Something thing in Model.Somethings)
{
    @Html.EditorFor(m => thing)
}

这在结果HTML中呈现为<input name="thing".....,这是没有用的.解决方案是使用for循环并通过模型的路径访问模型的属性,而不是将指针复制到实例,例如:

This is rendered in the resulting html as <input name="thing"..... which is useless. The solution here is to use a for loop and access the model's properties via their path rather than copying pointers to instances, such as:

for (int i = 0; i < Model.Somethings.Count; i++)
{
    @Html.EditorFor(m => Model.Somethings[i])
}

然后使用正确的<input name="Model.Somethings[i]".....进行渲染,并将被模型绑定器理解.

This is then rendered with the correct <input name="Model.Somethings[i]"..... and will be understood by the model binder.

我希望您在这里遇到的这个问题也很相似.您需要在属性中添加必要的访问器,以便可以在视图中呈现正确的名称和ID,并由活页夹拾取.

I expect this issue you're facing here is similar. You need to add the necessary accessors to your properties so that the correct names and ids can be rendered in your view and picked up by the binder.

我不确定您的类的确切定义,因此此示例不太可能完全正确.

I'm not sure of the exact definition of your class so this example is not likely to be completely right.

此类包括this [string index]方法,该方法将使用您的属性键作为索引来获取和设置元素:

This class includes a this[string index] method which will get and set the element using your property key as the index:

public class ProfileElements : List<ProfileElement>
{
    public ProfileElement this[string index]
    {
        get
        {
            return base.First(p => p.ProfileElementDefinition.Key == index);
        }
        set
        {
            base[index] = value;
        }
    }
}

在您看来,您可以这样使用:

And in your view, you could use this like:

@Html.TextBoxFor(model => model.ProfileVM.ProfileElements[ProfileElementKey.CompanyName.ToString()].Text)

希望这能满足您的需求.

Hopefully, this will do what you need.

这篇关于MVC ViewModel绑定构造与展平的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆