I am still new to MVC and still trying to get a grasp on the best way to do things. I realize at some point I'll probably need to switch to using Repositories or something but for now I have my EF Models and I am trying to use ViewModels in my Controllers.
I am trying to display a Grid and perform basic CRUD operations. I am using an EditorTemplate for the popup mode. Basically the Grid is supposed to display a set of items (Beamlines). One of the fields within a Beamline is an AllocationPanelID. The Beamline stores the AllocationPanelID but the full list of AllocationPanels is in a separate model. So my understanding of ViewModels is that I can combine data from multiple models into one View Model. This is where I am having trouble. I define that AllocationPanel IEnumerable<SelectListItem> in the View Model and connect it in the Controller but when it gets to it in the
View it has NULL as if it is never really getting hooked up to the data.
View Model: (shortened for breviety)
Controller: (only showing Index, Edit, and related methods)
View:
Editor Template: (shortened for breviety)
A lot of this code I got from different places and have manipulated to get it working. The GetAllocationPanels() method seems to hook the AllocationPanels IEnumerable that is defined in the View Model but I never actually call the GetAllocationPanels() method or see where to call it.
As the code currently exists, the Grid loads and when I try to edit a Beamline I get an error on the second to last line of the Editor Template, the DropDownListFor for the AllocationPanels. It gives me a ArgumentNullException. Value cannot be null. Parameter name: items.
I have also read that it might be better to have a View Model for the Beamline which would just contain the fields making up a Beamline, and then a second View Model for the Beamline listing which would have an instantiation for the first View Model and then also the other items like the AllocationPanels. I have tried that but could never seem to figure out how to type the View and Editor Template and also what should go in the Controller methods.
Any help is greatly appreciated.
The trouble is.
I am trying to display a Grid and perform basic CRUD operations. I am using an EditorTemplate for the popup mode. Basically the Grid is supposed to display a set of items (Beamlines). One of the fields within a Beamline is an AllocationPanelID. The Beamline stores the AllocationPanelID but the full list of AllocationPanels is in a separate model. So my understanding of ViewModels is that I can combine data from multiple models into one View Model. This is where I am having trouble. I define that AllocationPanel IEnumerable<SelectListItem> in the View Model and connect it in the Controller but when it gets to it in the
View it has NULL as if it is never really getting hooked up to the data.
View Model: (shortened for breviety)
public
class
BeamlineViewModel
{
public
decimal
ID {
get
;
set
; }
public
string
Description {
get
;
set
; }
public
Nullable<
decimal
> SortOrder {
get
;
set
; }
public
string
InsertionDevice {
get
;
set
; }
public
Nullable<
decimal
> AllocationPanelID {
get
;
set
; }
public
string
Status {
get
;
set
; }
public
IEnumerable<SelectListItem> AllocationPanels {
get
;
set
; }
public
IEnumerable<SelectListItem> StatusTypes =
new
List<SelectListItem>
{
new
SelectListItem {Value =
"A"
, Text =
"Available"
},
new
SelectListItem {Value =
"C"
, Text =
"Construction and Commissioning"
},
new
SelectListItem {Value =
"D"
, Text =
"Diagnostic and Instrumentation"
},
new
SelectListItem {Value =
"O"
, Text =
"Operational"
},
new
SelectListItem {Value =
"U"
, Text =
"Unused Port"
}
};
}
Controller: (only showing Index, Edit, and related methods)
public
ActionResult Index()
{
return
View(GetBeamlines());
}
public
ActionResult Edit(
int
id)
{
using
(MyEntities context =
new
MyEntities())
{
return
View(context.Beamlines.Find(id));
}
}
private
static
IEnumerable<BeamlineViewModel> GetBeamlines()
{
var context =
new
MyEntities();
return
context.Beamlines.Select(b =>
new
BeamlineViewModel
{
ID = b.ID,
Description = b.Description,
SortOrder = b.Sort_Order,
InsertionDevice = b.Insertion_Device,
AllocationPanelID = b.Allocation_Panel_ID,
Status = b.Status
});
}
public
ActionResult GetAllocationPanels()
{
using
(MyEntities context =
new
MyEntities())
{
var allocationPanels = context.Allocation_Panels.ToList();
var model =
new
BeamlineViewModel
{
AllocationPanels = allocationPanels.Select(m =>
new
SelectListItem { Value = m.ID.ToString(), Text = m.Description })
};
return
View(model);
}
}
View:
@model IEnumerable<MyProject.ViewModels.BeamlineViewModel>
@{
ViewBag.Title =
"Beamlines"
;
}
<h2>Beamlines</h2>
@(Html.Kendo().Grid(Model)
.Name(
"gvBeamlines"
)
.Columns(columns =>
{
columns.Command(command => { command.Edit(); }).Width(50);
columns.Bound(o => o.Description).Width(100);
columns.Bound(o => o.InsertionDevice).Title(
"Insertion Device"
);
columns.Bound(o => o.Status);
columns.Bound(o => o.EnergyRange).Title(
"Energy Range"
);
columns.Command(command => { command.Destroy(); }).Width(50);
})
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName(
"Beamline"
).Window(window => window.HtmlAttributes(
new
{ @style =
"width:700px;"
})))
.Pageable()
.Sortable()
.DataSource(dataSource => dataSource
.Server()
.Model(model => model.Id(o => o.ID))
.Create(create => create.Action(
"Create"
,
"Beamlines"
))
.Read(read => read.Action(
"Index"
,
"Beamlines"
))
.Update(update => update.Action(
"Edit"
,
"Beamlines"
))
.Destroy(destroy => destroy.Action(
"Delete"
,
"Beamlines"
))
)
)
Editor Template: (shortened for breviety)
@model MyProject.ViewModels.BeamlineViewModel
@Html.HiddenFor(model => model.ID)
<div
class
=
"editor-label"
>
@Html.Label(
"Beamline"
)
</div>
<div
class
=
"editor-field"
>
@Html.EditorFor(model => model.Description)
@Html.ValidationMessageFor(model => model.Description)
</div>
<div
class
=
"editor-label"
>
@Html.Label(
"Status"
)
</div>
<div
class
=
"editor-field"
>
@Html.DropDownListFor(model => model.Status,
new
SelectList(Model.StatusTypes,
"Value"
,
"Text"
),
"(Select One)"
)
@Html.ValidationMessageFor(model => model.Status)
</div>
<div
class
=
"editor-label"
>
@Html.Label(
"Sort Order"
)
</div>
<div
class
=
"editor-field"
>
@Html.EditorFor(model => model.SortOrder)
@Html.ValidationMessageFor(model => model.SortOrder)
</div>
<div
class
=
"editor-label"
>
@Html.Label(
"Insertion Device Beamline"
)
</div>
<div
class
=
"editor-field"
>
@Html.RadioButtonFor(model => model.InsertionDevice,
"Y"
)
@Html.Label(
"Yes"
)
@Html.RadioButtonFor(model => model.InsertionDevice,
"N"
)
@Html.Label(
"No"
)
@Html.ValidationMessageFor(model => model.InsertionDevice)
</div>
<div
class
=
"editor-label"
>
@Html.Label(
"Allocation Panel"
)
</div>
<div
class
=
"editor-field"
>
@Html.DropDownListFor(model => model.AllocationPanelID,
new
SelectList(Model.AllocationPanels,
"Value"
,
"Text"
),
"(Select One)"
)
@Html.ValidationMessageFor(model => model.AllocationPanelID)
</div>
A lot of this code I got from different places and have manipulated to get it working. The GetAllocationPanels() method seems to hook the AllocationPanels IEnumerable that is defined in the View Model but I never actually call the GetAllocationPanels() method or see where to call it.
As the code currently exists, the Grid loads and when I try to edit a Beamline I get an error on the second to last line of the Editor Template, the DropDownListFor for the AllocationPanels. It gives me a ArgumentNullException. Value cannot be null. Parameter name: items.
I have also read that it might be better to have a View Model for the Beamline which would just contain the fields making up a Beamline, and then a second View Model for the Beamline listing which would have an instantiation for the first View Model and then also the other items like the AllocationPanels. I have tried that but could never seem to figure out how to type the View and Editor Template and also what should go in the Controller methods.
Any help is greatly appreciated.
The trouble is.