简体   繁体   English

如何将下拉列表绑定到ASP.Net MVC C#中的动态生成的变量

[英]How to bind a drop down list to a dynamically generated variable in ASP.Net MVC C#

We have an application which uses dynamic custom properties to define attributes/properties of certain entities in the system. 我们有一个使用动态自定义属性定义系统中某些实体的属性的应用程序。

As such, there are some situations where we need to have form fields (usually drop down lists or check box lists) populated dynamically, ideally by specifying the custom property type in the view. 因此,在某些情况下,我们需要动态填充表单字段(通常是下拉列表或复选框列表),最好在视图中指定自定义属性类型。

This question is specifically about drop down lists. 这个问题专门关于下拉列表。

This is what we are trying to do: 这是我们正在尝试做的事情:

ViewModel: ViewModel:

public class SearchViewModel
{
    #region Properties

    public Dictionary<string, SelectList> CustomPropertySelectLists { get; set; }
    public Dictionary<string, string> SelectedCustomProperties { get; set; }

    #endregion

    #region Constructors

    public SearchViewModel()
    {
        //Create the SelectedCustomProperties list and pre-populate with a blank item for each CustomPropertyType
        SelectedCustomProperties = new Dictionary<string, string>();
        foreach (CustomPropertyType cpt in Core.GetCustomPropertyTypes())
        {
            SelectedCustomProperties.Add(cpt.CustomPropertyTypeId, string.Empty); 
        }
    }

    #endregion
}

Controller: 控制器:

public ActionResult Search(int searchId)
{
    var svm = new SearchViewModel();

    //Load selected custom property ids for this search
    if ( searchId > 0 )
    {
        Search s = Core.GetSearch(searchId);
        foreach ( CustomPropertyType cpt in Core.GetCustomPropertyTypes()) )
        {
            int cpid = s.GetBasicSearchCustomPropertyId(cpt.CustomPropertyTypeId);
            if ( cpid > 0 )
            {
                //NB assumes entries already present (i.e. were created in the constructor)
                svm.SelectedCustomProperties[cpt.CustomPropertyTypeId] = cpid.ToString();
            }
        }
    }

    //Load lists of all custom property select lists so the view can just dynamically use whichever ones it wants
    svm.CustomPropertySelectLists = Core.GetSelectListsForAllCustomPropertyTypes();

    return View(svm);
}

And then in the view: 然后在视图中:

@using (Html.BeginForm())
{
    <fieldset>
        <div class="row">
            <div class="col">
                @Html.DropDownListFor(m => m.SelectedCustomProperties["Sector"], Model.CustomPropertySelectLists["Sector"], "Sector", new { @class = "browser-default" })
            </div>
            <div class="col">
                @Html.DropDownListFor(m => m.SelectedCustomProperties["Location"], Model.CustomPropertySelectLists["Location"], "Location", new { @class = "browser-default" })
            </div>
        </div>
    </fieldset>
}

This all works in terms of populating the dynamically defined drop down lists. 所有这些工作都可以填充动态定义的下拉列表。 We could even dynamically define which drop down lists to render at run time by looping over custom property types which have been defined to appear in certain parts of the system and/or for certain entities using configuration stored elsewhere in the system. 我们甚至可以通过循环定义自定义属性类型来动态定义要在运行时呈现的下拉列表,这些自定义属性类型已定义为出现在系统的某些部分和/或使用存储在系统其他位置的某些实体显示。

However, the selected value for the drop down lists is not getting picked up, presumably because it is trying to bind to something like m => m.SelectedCustomProperties["Sector"] rather than to a scalar variable property. 但是,下拉列表中的选定值未获取,可能是因为它试图绑定到m => m.SelectedCustomProperties["Sector"]而不是绑定到标量变量属性。

I realise that in our ViewModel we could have something like: 我意识到在我们的ViewModel中,我们可以有类似以下内容:

public string SelectedCustomPropertyIdSector { get; set; }

Then populate SelectedCustomPropertyIdSector in the controller and then bind to the drop down lists with m => m.SelectedCustomPropertyIdSector , but this would somewhat undermine the dynamic nature of the custom properties in the system as we'd have to be hard coding properties to the ViewModel/Controller depending on the use. 然后在控制器中填充SelectedCustomPropertyIdSector ,然后使用m => m.SelectedCustomPropertyIdSector绑定到下拉列表,但这会在一定程度上破坏系统中自定义属性的动态特性,因为我们必须对ViewModel进行属性编码/ Controller取决于用途。

Ideally, we want to be able to write generic, reusable models and controller code which is only concerned with our "CustomProperty" entities in the database, and then have the views specify the specific custom properties to use by referencing the custom property type ids in the view markup (and/or by dynamically deciding which drop down lists to render at run time). 理想情况下,我们希望能够编写仅与数据库中的“ CustomProperty”实体有关的通用,可重用的模型和控制器代码,然后让视图通过引用中的自定义属性类型ID来指定要使用的特定自定义属性。视图标记(和/或通过动态确定要在运行时呈现的下拉列表)。

This will only be possible if we can get the DropDownListFor property to bind to something in a dynamically generated list (referenced by custom property type id), rather than a scaler variable as is usually the case, but this doesn't seem to be possible? 仅当我们可以将DropDownListFor属性绑定到动态生成的列表(由自定义属性类型id引用)中的某物(而不是通常情况下的缩放器变量)时,这才可能实现,但这似乎是不可能的?

I'm relatively new to MVC, but in my experience the Drop Down Lists want to update a well known property of the view model, the scalar SelectedCustomPropertyIdSector you mentioned. 我是MVC的新手,但以我的经验,下拉列表希望更新视图模型的知名属性,即您提到的标量SelectedCustomPropertyIdSector。

Have you tried including SelectedCustomProperties as a HiddenFor to make sure the list itself gets back to the action after post? 您是否尝试过将SelectedCustomProperties包含为HiddenFor,以确保列表本身在发布后返回操作?

It's possible that it's not working because the view model doesn't remember the list after the page is rendered, and without the scalar variable to attach to that may be the issue. 可能无法正常工作是因为视图模型在页面呈现后无法记住列表,并且没有标量变量附加到该列表中可能是问题所在。

It looks as if you have a problem with the Model Binding. 看来您对模型绑定有问题。 The Html that is rendered cannot be bound back into the model when you post it. 发布的Html在发布时无法绑定回模型。

You might want to take a look at thisblog post http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ 您可能想看一下此博客文章http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

I've not bound items to a Dictionary myself, but have to an IEnumerable<Object> . 我自己没有将项目绑定到Dictionary,而是必须绑定到IEnumerable<Object> You could try creating a CustomPropertyViewModel 您可以尝试创建CustomPropertyViewModel

public class CustomPropertyViewModel
{
    public string Filter { get; set; }
    public string SelectedValue { get; set; }
    public SelectList SelectList { get; set; }
}

Your SearchViewModel would contain 您的SearchViewModel将包含

IEnumerable<CustomerPropertyViewModel> CustomProperties { get; set; }

and you would render in in the view something like 并且您将在视图中呈现类似

@for (int i = 0; i < Model.CustomPropeties.Count(); i++)
{
    @Html.HiddenFor(x => Model.CustomProperties[i].Filter
    @Html.DropdownListFor(x => Model.CustomProperties[i].SelectedValue,
        Model.CustomProperties[i].SelectList)
}

You can try to use @Html.DropDownList helper instead of @Html.DropDownListFor 您可以尝试使用@Html.DropDownList而不是@Html.DropDownListFor

 @Html.DropDownList("Sector", Model.CustomPropertySelectLists["Sector"], "Sector", new { @class = "browser-default" })

This way in the submitted value will be available in Postback action as Request.Form["Sector"] 这样提交的值将在回发操作中作为Request.Form["Sector"]

Then you need to map it to your properties. 然后,您需要将其映射到您的属性。 So something like that should work( I assume that you can write some code to it automatically because you have your custom property names): 所以类似的事情应该起作用(我假设您可以自定义属性名称,因此可以自动向其中编写一些代码):

SelectedCustomProperties["Sector"] = Request.Form["Sector"]

Edit You can automate dropdown generation and sequential model binding: 编辑您可以自动执行下拉列表生成和顺序模型绑定:

@for(var key in Model.CustomPropertySelectLists.Keys)
{
    @Html.DropDownList(key , Model.CustomPropertySelectLists[key], key , new { @class = "browser-default" })
}

in your postback action: 在您的回发操作中:

var types = Core.GetCustomPropertyTypes()
foreach(var t in types)
{
    if(Request.Form.ContainsKey(t.CustomPropertyTypeId))
    {
        SelectedCustomProperties[t.CustomPropertyTypeId] = Request.Form[t.CustomPropertyTypeId]
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM