视图中的MVC4模型具有嵌套数据 - 无法在模型中获取数据

时间:2012-10-04 14:17:01

标签: c# asp.net asp.net-mvc asp.net-mvc-4 html-helper

我有一个模型定义,根据IEnumerable为我提供一个带有RadioButtons列表的视图。

在该模型中,我想显示一个复选框列表,这些复选框将根据所选项目而有所不同。最后,一旦用户从可用的复选框中选择,将在同一视图中存在Textarea,其中一些动态文本基于所选的CheckBox。我们最终应该得到的是每层次表。

布局是这样的,RadioButtonList位于第一个表格单元格中,CheckBoxList位于中间表格单元格中,而Textarea位于右表格单元格中。

如果有人能指导我的模型视图应该是什么来实现这个结果,我会非常高兴...

以下是我的代码:

//
// View Model for implementing radio button list

public class RadioButtonViewModel
{
    // objects
    public List<RadioButtonItem> RadioButtonList { get; set; }
    public string SelectedRadioButton { get; set; }
}

//
// Object for handling each radio button

public class RadioButtonItem
{
    // this object
    public string Name { get; set; }
    public bool Selected { get; set; }
    public int ObjectId { get; set; }
    // columns
    public virtual IEnumerable<CheckBoxItem> CheckBoxItems { get; set; }
}

//
// Object for handling each checkbox

public class CheckBoxViewModel
{
    public List<CheckBoxItem> CheckBoxList { get; set; }
}

//
// Object for handling each check box

public class CheckBoxItem
{
    public string Name { get; set; }
    public bool Selected { get; set; }
    public int ObjectId { get; set; }
    public virtual RadioButtonItem RadioButtonItem { get; set; }
}

和视图

@model IEnumerable<EF_Utility.Models.RadioButtonItem>

@{
    ViewBag.Title = "Connect";
    ViewBag.Selected = Request["name"] != null ? Request["name"].ToString() : "";
}

@using (Html.BeginForm("Objects" , "Home", FormMethod.Post) ){

@Html.ValidationSummary(true)

<table>
    <tbody>
        <tr>
            <td style="border: 1px solid grey; vertical-align:top;">

                <table>
                    <tbody>
                        <tr>
                            <th style="text-align:left; width: 50px;">Select</th>
                            <th style="text-align:left;">View or Table Name</th>
                        </tr>
                        @{
                        foreach (EF_Utility.Models.RadioButtonItem item in @Model )
                        {
                        <tr>
                            <td>
                                @Html.RadioButton("RadioButtonViewModel.SelectedRadioButton", 
                                    item.Name, 
                                    ViewBag.Selected == item.Name ? true : item.Selected, 
                                    new { @onclick = "this.form.action='/Home/Connect?name=" + item.Name + "'; this.form.submit(); " })
                            </td>
                            <td>
                                @Html.DisplayFor(i => item.Name)
                            </td>
                        </tr>
                        }
                        }
                    </tbody>
                </table>

            </td>
            <td style="border: 1px solid grey; width: 220px; vertical-align:top; @(ViewBag.Selected == "" ? "display:none;" : "")">

                <table>
                    <tbody>
                        <tr>
                            <th>Column
                            </th>
                        </tr>
                        <tr>
                            <td><!-- checkboxes will go here -->
                            </td>
                        </tr>
                    </tbody>
                </table>

            </td>
            <td style="border: 1px solid grey; vertical-align:top; @(ViewBag.Selected == "" ? "display:none;" : "")">
                <textarea name="output" id="output" rows="24" cols="48"></textarea>
            </td>
        </tr>
    </tbody>
</table>
}

和相关的控制器

public ActionResult Connect() 
    {
        /* TEST SESSION FIRST*/ 
        if(  Session["connstr"] == null)
            return RedirectToAction("Index");
        else
        {
            ViewBag.Message = "";
            ViewBag.ConnectionString = Server.UrlDecode( Session["connstr"].ToString() );
            ViewBag.Server = ParseConnectionString( ViewBag.ConnectionString, "Data Source" );
            ViewBag.Database = ParseConnectionString( ViewBag.ConnectionString, "Initial Catalog" );

            using( var db = new SysDbContext(ViewBag.ConnectionString))
            {
                var objects = db.Set<SqlObject>().ToArray();

                var model = objects
                    .Select( o => new RadioButtonItem { Name = o.Name, Selected = false, ObjectId = o.Object_Id, CheckBoxItems = Enumerable.Empty<EF_Utility.Models.CheckBoxItem>() } )
                    .OrderBy( rb => rb.Name );

                return View( model );
            }
        }
    }

我似乎缺少的是,我的Connect()方法中的代码将带来数据上下文;那时,为视图设置Html应该是相当简单的。

EDIT **所以我需要将RadioButtonItem绑定到视图,如下所示,除了我的CheckBoxList不是空集。

    //
    // POST: /Home/Connect/

    [HttpPost]
    public ActionResult Connect( RadioButtonItem rbl )
    {
        /* TEST SESSION FIRST*/
        if ( Session["connstr"] == null )
            return RedirectToAction( "Index" );
        else
        {
            ViewBag.Message = "";
            ViewBag.ConnectionString = Server.UrlDecode( Session["connstr"].ToString() );
            ViewBag.Server = ParseConnectionString( ViewBag.ConnectionString, "Data Source" );
            ViewBag.Database = ParseConnectionString( ViewBag.ConnectionString, "Initial Catalog" );

            using ( var db = new SysDbContext( ViewBag.ConnectionString ) )
            {
                var objects = db.Set<SqlObject>().ToArray();

                var model = objects
                    .Select( o => new RadioButtonItem { Name = o.Name, Selected = false, ObjectId = o.Object_Id, CheckBoxItems = Enumerable.Empty<EF_Utility.Models.CheckBoxItem>() } )
                    .OrderBy( rb => rb.Name );

                return View( model );
            }
        }
    }

2 个答案:

答案 0 :(得分:2)

你有两个问题。

首先,您不是在ViewModel的构造函数中新建一个空列表。默认模型绑定程序不会实例化子对象,因此必须在构造函数中执行此操作。

其次,在视图中使用foreach的方式没有为模型绑定器正确命名输入以将它们绑定到列表。

你有几个选择。首选方法是使用EditorTemplate。在〜/ Views / Shared文件夹中创建一个名为EditorTemplates的文件夹,然后在其中创建一个名为RadioButtonItem.cshtml的文件,然后将foreach中的代码放在该文件中,并将其替换为Html.EditorFor(m => m.RadioButtonItems)

或者,您必须使用for语句,并将项目作为索引引用到列表中,类似于下面。

@for(int i = 0; i < Model.RadioButtonItems.Count; i++)
{
    .....
    <label>
    @Html.RadioButtonFor(m => m.RadioButtonList[i].Selected, true) 
    @Html.RadioButtonFor(m => m.RadioButtonList[i].Selected, false)
    m.RadioButtonList[i].Name
    </label>
    ..... 
}

问题是您没有创建正确的有线格式。请参阅以下文章:

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

答案 1 :(得分:0)

以下是我最终需要做的事情:

使用相关的Model类定义一个新的Controller方法来处理回发,并在View中处理嵌套的相关Checkbox:

    @Html.Raw(ViewBag.TextBoxes)

为了清楚起见,我还将类从'RadioButtonItem'重命名为'TableOrViewItem'。 这是我加入的Controller方法:

    [HttpPost]
    public ActionResult Connect( TableOrViewItem rbl )
    {
        /* TEST SESSION FIRST*/
        if ( Session["connstr"] == null )
            return RedirectToAction( "Index" );
        else
        {
            ViewBag.Message = "";
            ViewBag.ConnectionString = Server.UrlDecode( Session["connstr"].ToString() );
            ViewBag.Server = ParseConnectionString( ViewBag.ConnectionString, "Data Source" );
            ViewBag.Database = ParseConnectionString( ViewBag.ConnectionString, "Initial Catalog" );
            ViewBag.Selected = Request["name"] != null ? Request["name"].ToString() : "";
            ViewBag.ObjectID = Request["id"] != null ? Request["id"].ToString() : "";

            using ( var dbo = new SqlObjectContext( ViewBag.ConnectionString ) )
            {

                // obtain this item's objectid
                string CurrentObjectId = Request["id"].ToString();
                int CurrentID = StringToInt( CurrentObjectId );

                // populate Checkbox Area

                var rawColumns = dbo.Set<SqlColumn>()
                    .Where( column => column.ObjectId == CurrentID )
                    .OrderBy( o => o.ColumnId )
                    .ToList();

                string htmlColumns = string.Empty;

                foreach ( EF_Utility.Models.SqlColumn item in rawColumns )
                {
                    htmlColumns += "<input checked=\"checked\" id=\"RadioButtonViewModel_CheckBox" 
                        + item.ColumnId + "\" name=\"CheckBox_" + item.ColumnId 
                        + "\" type=\"checkbox\" value=\"" + item.Name + "\">" 
                        + item.Name + " <br>";
                }
                if(! string.IsNullOrEmpty(htmlColumns))
                {
                    htmlColumns += "<br /><center><input type=\"submit\" value=\"Generate\" name=\"btnGenerate\" id=\"btnGenerate\" /></center>";
                    htmlColumns += "<input type=\"hidden\" name=\"id\" value=\"" + CurrentObjectId + "\" />";
                    htmlColumns += "<input type=\"hidden\" name=\"name\" value=\"" + ViewBag.Selected + "\" />";
                }

                ViewBag.TextBoxes = htmlColumns;

                /*var ColumnItemList = columns
                    .Select( c => new ColumnItem { Name = c.Name, Selected = true, ObjectId = c.ObjectId } )
                    .Where( tvi => tvi.ObjectId == CurrentID );
                */

                // Check to see if the user wants the list generated

                if(Request["btnGenerate"] != null)
                {
                    string sNewLine = System.Environment.NewLine;
                    string htmlText = "[Table( \"" + ViewBag.Selected +"\" )]" + sNewLine +
                        "public class " + POCOFormated( ViewBag.Selected ) + sNewLine + "{";
                    string tempColumn = string.Empty;
                    string tempName = string.Empty;

                    foreach(string key in Request.Form)
                    {
                        if(!key.StartsWith("CheckBox_")) continue;

                        tempName = POCOFormated( Request.Form[key] );
                        htmlText = htmlText +
                            sNewLine + "\t" +
                            "public " + "...fieldtype..." + " " + tempName.Trim() + " { get; set; }" +
                            sNewLine; 
                    }                       
                    htmlText = htmlText + sNewLine + "}";

                    ViewBag.TextArea = htmlText;
                }

                var objects = dbo.Set<SqlObject>().ToArray();

                var model = objects
                    .Select( o => new TableOrViewItem { Name = o.Name, Selected = false, ObjectId = o.ObjectId } )
                    .OrderBy( rb => rb.Name );


                return View( model );
            }
        }
    }