Object reference error trying to use RenderPartial - asp.net-mvc-3

I have a main view using a ViewModel. Inside the ViewModel I do this (Edited to show complete ViewModel):
namespace MyNameSpace.ViewModels
{
public class MyViewModel
{
public ModelOne ModelOne { get; set; }
public ModelTwo ModelTwo { get; set; }
}
}
On my main view I do this (EDIT: Added #Html.Hidden code):
#using MyNameSpace.ViewModels
#using MyNameSpace.Models
#model MyViewModel
...
#using (Html.BeginFormAntiForgeryPost())
{
#Html.Hidden("myData", new MvcSerializer()
.Serialize(Model, SerializationMode.Signed))
....
<div>
#{Html.RenderPartial("_MyCheckBox",
Model.ModelTwo, new ViewDataDictionary());}
</div>
}
....
My partial view is:
#using MyNameSpace.Models
#model ModelTwo
<div>
<fieldset>
<div class="editor-label">
#Html.LabelFor(x => x.MyCheckBox)</div>
<div class="editor-field">
<select multiple="multiple" id="#Html.FieldIdFor(x =>
x.MyCheckBox)" name="#Html.FieldNameFor(x =>
x.MyCheckBox)">
#foreach (MyEnum item in Enum.GetValues(typeof(MyEnum)))
{
var selected = Model.MyCheckBox.Contains(item); //ERROR HERE
<option value="#((int)item)" #if (selected)
{<text>selected="selected"</text>}>
#T(item.ToString())
</option>
}
</select>
</div>
</fieldset>
</div>
I am getting the Object reference not set to an instance ... error and am not sure how to correct it.
Originally, I had that <fieldset> inside my main view and was getting that error. I thought it was because of the two models and that's why I placed it in a partial view. But only to discover I am running into the same problem.
I am not setting the MyCheckBox in my partial view on the line var selected = Model.MyCheckBox.Contains(item); properly.
Any thoughts?
EDIT (Adding MyCheckBox code)
Here is MyCheckBox inside ModelOne.cs:
[Mandatory(ErrorMessage = "Please select at least one option")]
[Display(Name = "Please select one ore more options")]
[MySelector]
public virtual int MyCheckBox { get; set; }
And here it is inside ModelTwo.cs:
private IList<MyEnum> _myEnum;
public IList<MyEnum> MyCheckBox
{
get
{
if (_myEnum== null)
{
_myEnum= new List<MyEnum>();
foreach (MyEnumitem in Enum.GetValues(typeof(MyEnum)))
{
if (((MyEnum)Record.MyCheckBox& item) == item)
_myEnum.Add(item);
}
}
return _myEnum;
}
set
{
_myEnum= value;
Record.MyCheckBox= 0;
foreach (var item in value)
{
Record.MyCheckBox|= (int)item;
}
}
}
Please note, I am using Orchard (hence the Record) which, in turn, uses NHibernate. I don't believe that is relevant, but I could be wrong. The MyCheckBox code is using [Flags] attribute of enum and storing the value as an int in the DB (hence the proxy). Here is what the enum would look like:
MyEnum.cs:
[Flags]
public enum MyEnum
{
[Display(Name="Name 1")]
Enum1 = 1,
[Display(Name="Name 2")]
Enum2 = 2,
[Display(Name="Name 3")]
Enum3 = 4,
[Display(Name="Name 4")]
Enum4 = 8,
[Display(Name="Name 5")]
Enum5 = 16
}
MyController.cs
private MyViewModel myData;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var serialized = Request.Form["myData"];
if (serialized != null) //Form was posted containing serialized data
{
myData= (MyViewModel)new MvcSerializer().Deserialize
(serialized, SerializationMode.Signed);
TryUpdateModel(myData);
}
else
myData= (MyViewModel)TempData["myData"] ?? new MyViewModel();
TempData.Keep();
}
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.Result is RedirectToRouteResult)
TempData["myData"] = myData;
}
Then in the particular Action within *MyController.cs:
public ActionResult Step5(string backButton, string nextButton)
{
if (backButton != null)
return RedirectToAction("Step4");
else if ((nextButton != null) && ModelState.IsValid)
return RedirectToAction("Confirm");
else
return View(myData);
}

Related

views for select list contained within a viewmodel and validation

My Scenario :
My Model is "Item" which contain 0 or many number of taxes (Model "Tax")
"Item" --> has 0 or n --> "Tax"
I have a View Model for MVC named "VMItem" which has an object of "Item", all taxes ("TaxDic") and selected taxes ("Taxes"). MVC page is bind to this view model ("ViewItem").
Requirement :
I want the MVC to display a list box of all taxes and enable user to select relevant tax for each item when he create the item.
Below is my code,
Reference to the following codes, ListBox which is for Taxes is not mandatory field. But when I submitted the form with some selection on ListBox, it shows red box around the ListBox and if I select nothing on ListBox and submit, there is no error it seems.
please have a look at the following scenario.. if there is any better way to achieve this, please someone guide me.
model
public class Item
{
[Display(Name="Item ID")]
public virtual Guid ItemID { get; set; }
[Required]
[Display(Name = "Name")]
public virtual string Name { get; set; }
[Required]
[Display(Name="Price")]
public virtual decimal Price { get; set; }
public virtual IEnumerable<Tax> Taxes { get; set; }
}
View Model
public class VMItem
{
public Item Item { get; set; }
public IEnumerable<Tax> Taxes { get; set; }
public IEnumerable<SelectListItem> TaxDic { get; set; }
}
Function to generate Select list item in the controller class
private VMItem GenerateViewModel(Item Item)
{
IEnumerable<Tax> Taxes = TaxServices.FindAll();
IList<SelectListItem> taxDic = new List<SelectListItem>();
// Generating Taxes and taxDic here..
VMItem VmItem = new VMItem
{
Item = Item,
Taxes = Taxes,
TaxDic = taxDic
};
return VmItem;
}
Contorller Action
// GET: /Product/Add
public ActionResult Add()
{
return View(GenerateViewModel(new Item()));
}
[HttpPost]
public ActionResult Add(VMItem collection)
{
Item item = new Item();
try
{
if(ModelState.IsValid)
{
item = collection.Item;
var taxes = collection.Taxes;
return View(GenerateViewModel(collection.Item));
}
// else..
}
// catch...
}
Views
<% using (Html.BeginForm()) { %>
<!-- more codes for other fields -->
<%: Html.ListBoxFor(model => model.Taxes, Model.TaxDic) %>
<!-- submit button goes below -->
<% } %>
This looks like a many-to-many relationship so first check if your tax class looks like this:
public class Tax
{
public Guid TaxId { get; set;}
public virtual ICollection<Item> Items { get; set;}
}
Then inside your OnModelCreating function in the context class add this:
modelBuilder.Entity<Item>()
.HasMany(i => i.Taxes).WithMany(t => t.Items)
.Map(t => t.MapLeftKey("ItemId")
.MapRightKey("TaxId")
.ToTable("ItemsTaxes"));
ViewModel
public class ItemTaxViewModel
{
public Item item { get; set; }
public virtual ICollection<AssignedTaxes> Taxes { get; set; }
}
public class AssignedTaxes
{
public int TaxId { get; set; }
public bool Assigned { get; set; }
}
Controller Action
public ActionResult Create()
{
var newItemVM = new ItemTaxViewModel
{
Item = new Item(),
Taxes = PopulateTaxes()
};
return View(newItemVM);
}
[HttpPost]
public ActionResult Create(ItemTaxViewModel itemTaxViewModel)
{
if(ModelState.IsValid)
{
var item = new Item();
item = itemTaxViewModel.Item;
AddOrUpdateTaxes(item, itemTaxViewModel.Taxes);
context.Items.Add(item);
context.SaveChanges();
return RedirectToAction("Index");
}
return View(itemTaxViewModel);
}
Helper Methods
private List<AssignedTaxes> PopulateTaxes()
{
var taxes = context.Taxes;
var assignedTaxes = new List<AssignedTaxes>();
foreach(var tax in taxes)
{
assignedTaxes.Add(new AssignedTaxes
{
TaxId = tax.TaxId,
Assigned = false
});
}
return assignedTaxes;
}
private void AddOrUpdateTaxes(Item item, ICollection<AssignedTaxes> assignedTaxes)
{
foreach(var assignedTax in assignedTaxes)
{
if(assignedTax.Assigned)
{
item.Taxes.Add(context.Taxes.Single(t => t.TaxId == assignedTax.TaxId));
}
}
}
EditorTemplate under the /Views/Shared/EditorTemplates
#model AssignedTaxes
#using projectName.ViewModels
<fieldset>
#Html.HiddenFor(model => model.TaxId)
#Html.CheckBoxFor(model => model.Assigned)
</fieldset>
View
<div class="editor-field">
#Html.EditorFor(model => model.Taxes)
<div class="editor-field">
Seems likes a lot of work but it's one of the cleanest ways to implement many-to-many checkboxes that I've come up with after going through many tutorials.
#Luis, your way looks well but it is too complicated and at the end you ended it with checkbox. May be it is better way. I came up with a solution and it was simple enough to me. I post it below. Please give me a feedback on it whether I should keep going with it or need improvement.
Controller
IEnumerable<Tax> Taxes = _TaxServices.FindTax();
IList<SelectListItem> taxDic = new List<SelectListItem>();
foreach (Tax tax in Taxes)
{
SelectListItem item = new SelectListItem();
item.Value = tax.TaxID.ToString();
item.Text = tax.Name;
taxDic.Add(item);
}
VMItem VmItem = new VMItem
{
Item = Item,
TaxDic = taxDic,
};
// Adding selected taxes to the list
IList<int> SelectedTaxes = new List<int>();
if (Item.Taxes != null && Item.Taxes.Count > 0)
{
foreach (Tax tax in Item.Taxes)
{
SelectedTaxes.Add(tax.TaxID);
}
}
VmItem.SelectedTax = SelectedTaxes;
return view(VmItem);
View
<%: Html.ListBoxFor(model => model.SelectedTax, Model.TaxDic) %>
Controller [HttpPost]
item.Taxes = new Iesi.Collections.Generic.HashedSet<Tax>();
if (vmItem.SelectedTax.Count() > 0)
{
IEnumerable<int> SelectedTaxesIDs = vmItem.SelectedTax.ToList();
foreach (int n in SelectedTaxesIDs)
{
item.Taxes.Add(_TaxServices.FindTax(n));
}
}
Please give feedback on this way.
Thanks.

Display Template For Generics - View is not found

I have the following classes:
public class Widget
{
public string Name { get; set; }
}
GenericModel
public class GenericModel<T>
{
public List<T> Data { get; set; }
}
My Controller action is:
public ActionResult Simple()
{
var model = new GenericModel<Widget>()
{
Data = new List<Widget>
{
new Widget {Name = "a"}
}
};
return View(model);
}
And my view is:
#model MyApp.GenericModel<MyApp.Widget>
#{
ViewBag.Title = "Simple";
}
<h2>Simple</h2>
#Html.DisplayFor(m=>m)
I have a file called GenericModel.cshtml in Views/Shared/DisplayTemplate folder:
#model MyApp.GenericModel<MyApp.Widget>
<ul>
#for (int i = 0; i < Model.Data.Count; i++ )
{
<li>
#Html.EditorFor(m=> Model.Data[i].Name)
</li>
}
</ul>
This view can not be found. I see when I print out the name of the type of my model I get "GenericModel1". Seeing that, I renamed my template "GenericModel1.cshtml". This seems like a bit of a hack, is there an easier way to find this display template without resorting to this?
You have to set it in your viewstart:
#Code
Layout = "~/Views/Shared/DisplayTemplate.cshtml"
End Code
Note: The above is VB.
You can also pass it via your controller like this:
public ActionResult Simple()
{
var model = new GenericModel<Widget>()
{
Data = new List<Widget>
{
new Widget {Name = "a"}
}
};
return View("", "DisplayTemplate", model);
}

CheckBoxList does not update the model

I defined a Person entity:
public partial class Person
{
public string persID { get; set; }
public string last_name { get; set; }
public string driving_licence { get; set; }
}
where the driving licence is as follows:
public class DrivingLicence
{
public string drivingLicenceValue { get; set; }
public string drivingLicenceText { get; set; }
public DrivingLicence(string paValue, string paText)
{
drivingLicenceValue = paValue;
drivingLicenceText = paText;
}
}
having a repository where is defined this function:
public List<DrivingLicence> GetAll()
{
try
{
var drivingLicenceList = new List<DrivingLicence>();
DrivingLicence oneDrivingLicence = new DrivingLicence("A", "A");
drivingLicenceList.Add(oneDrivingLicence );
oneDrivingLicence = new DrivingLicence("B", "B");
drivingLicenceList.Add(oneDrivingLicence );
oneDrivingLicence = new DrivingLicence("C", "C");
drivingLicenceList.Add(oneDrivingLicence );
oneDrivingLicence = new DrivingLicence("D", "D");
drivingLicenceList.Add(oneDrivingLicence );
return drivingLicenceList;
}
catch (Exception)
{
throw new Exception("An error occured. Failed to Get the list.");
}
}
Now: I want the driving licences displayed as a CheckBoxList and on submit I want the person to get assigned the checked driving licence categories, e.g.: the "A" and "C" categories are selected, the resulting person.driving_licence must be "AC".
The problem is that this does not happen, the person is created but the driving_licence property is empty. I payed attention that the check boxes name be identical to that of the corresponding property (Person.driving_licence).
Is that an error in the present code? Or should I modify the Person entity?
Thank you for your advice.
Here is the view model:
public class PersonFormViewModel
{
// Properties
public Person person { get; set; }
public SelectList DrivingLicenceList { get; set; }
public string ActionToPerform { get; set; }
public PersonFormViewModel() { }
// Constructor
public PersonFormViewModel(Person pPerson, SelectList pDrivingLicenceList)
{
person= pPerson;
DrivingLicenceList = pDrivingLicenceList;
if (String.IsNullOrEmpty(person.persID))
{
ActionToPerform = "Create";
}
else
{
ActionToPerform = "Edit";
}
}
}
The controller:
//
// GET: /Person/Create
[Authorize]
public ActionResult Create()
{
Person person = new Person();
SelectList drvLicenceList = new SelectList(drvLicenceRepository.GetAll(), "drivingLicenceValue", "drivingLicenceText");
return View("Create", new PersonFormViewModel(person, drvLicenceList));
}
//
// POST: /Person/Create
[HttpPost, Authorize]
public ActionResult Create(PersonFormViewModel model)
{
Person person = model.person;
SelectList drvLicenceList = new SelectList(drvLicenceRepository.GetAll(), "drivingLicenceValue", "drivingLicenceText");
if (ModelState.IsValid)
{
try
{
db.Entry(person).State = EntityState.Added;
db.SaveChanges();
return RedirectToAction("Details");
}
catch (...)
{
...
}
}
return View("Create", new PersonFormViewModel(person, drvLicenceList));
}
And the view:
#model MyApp.ViewModels.PersonFormViewModel
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm())
{
#Html.ValidationSummary(false, "Errors occured.")
<fieldset>
<legend>Fill in your details</legend>
#Html.LabelFor(model => model.person.last_name)
#Html.TextBoxFor(model => model.person.last_name)
#Html.ValidationMessageFor(model => model.person.last_name, "*")
#Html.HiddenFor(model => model.person.persID)
#foreach (var ctg in (Model.DrivingLicenceList))
{
<input type="checkbox" name="driving_licence" value=ctg.value />#ctg.Text
}
<input type="submit" value="Sauvegarder" class="submit" />
</fieldset>
}
I would use a collection property in order to store the selected driving licence categories (multiple checkboxes can be selected => collection):
public partial class Person
{
public string persID { get; set; }
public string last_name { get; set; }
public string[] driving_licence { get; set; }
}
and then you will need to fix the name of the checkbox in order for it to bind correctly:
#foreach (var ctg in Model.DrivingLicenceList)
{
<input type="checkbox" name="person.driving_licence" value="#ctg.Value" />
#ctg.Text
}
and if you wanted to preserve the selected values you will need to set the checked property accordingly:
#foreach (var ctg in Model.DrivingLicenceList)
{
<input type="checkbox" name="person.driving_licence" value="#ctg.Value" #((Model.person.driving_licence ?? Enumerable.Empty<string>()).Contains(ctg.Value) ? "checked=\"checked\"" : "") />
#ctg.Text
}
This being said, we now have a working solution but it is far from anything I would content myself with and stop here. From now on we could start refactoring this mess in order to comply with C# naming conventions (things like property names start with capital letter, ...), introduce real view models (which do not reference domain models), custom HTML helpers that will generate this checkbox lists to avoid writing loops in the views and hardcoding checkboxes, ...

How to use EditorForModel and DataAnnotations for complex types in a wrapping ViewModel?

I have a ViewModel wrapping two complex types:
public class EditProductViewModel
{
public ProductData ProductData { get; set; }
public FridgeContent FridgeContent { get; set; }
}
and this view:
#model EditProductViewModel
#using (Html.BeginForm("Edit", "ProductData", FormMethod.Post))
{
#Html.EditorForModel()
[...]
}
ProductData and FridgeContent contain POCO properties with DataAnnotations like this:
public class FridgeContentMetadata : DatabaseEntityMetadataBase
{
[Required]
[HiddenInput(DisplayValue = false)]
public int ProductDataId { get; set; }
[Required]
[UIHint("StringReadOnly")]
public int ScaleId { get; set; }
[Required]
[UIHint("StringReadOnly")]
[Range(0.01, float.MaxValue, ErrorMessage = "The weight of a product must be positive.")]
public float Weight { get; set; }
[...]
}
I want to edit both ProductData and FridgeContent in the EditProductView using the appropriate data annotations from those classes and the EditorForModel() method (I don't want to generate the templates myself). I therefore created the templates ProductData.cshtml and FridgeContent.cshtml in /Views/Shared/EditorTemplates/:
#model FridgeContent
#Html.EditorForModel()
Unfortunately, the view for EditProductViewModel is empty (no errors raised). If I use EditorForModel for either FridgeContent or ProductData alone, it's working fine. I also tried adding [UIHInt("..")] annotations to EditProductViewModel but that doesn't make a difference.
What am I missing?
#model EditProductViewModel
#using (Html.BeginForm("Edit", "ProductData", FormMethod.Post))
{
#Html.EditorFor(o=> o.ProductData )
#Html.EditorFor(o=> o.FridgeContent )
}
or create an edit template for you ViewModel containing these two lines
#Html.EditorFor(o=> o.ProductData )
#Html.EditorFor(o=> o.FridgeContent )
UPADTE:
Oh got it finally because the rendering engine will not go more that one step in object hierarchy, you can find it in asp.net mvc code also.
Check the MVC 3.0 Source Code Here:
There is a file named DefaultEditorTemplates.cs which contains this method:
internal static string ObjectTemplate(HtmlHelper html, TemplateHelpers.TemplateHelperDelegate templateHelper) {
ViewDataDictionary viewData = html.ViewContext.ViewData;
TemplateInfo templateInfo = viewData.TemplateInfo;
ModelMetadata modelMetadata = viewData.ModelMetadata;
StringBuilder builder = new StringBuilder();
if (templateInfo.TemplateDepth > 1) { // DDB #224751
return modelMetadata.Model == null ? modelMetadata.NullDisplayText : modelMetadata.SimpleDisplayText;
}
foreach (ModelMetadata propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo))) {
if (!propertyMetadata.HideSurroundingHtml) {
string label = LabelExtensions.LabelHelper(html, propertyMetadata, propertyMetadata.PropertyName).ToHtmlString();
if (!String.IsNullOrEmpty(label)) {
builder.AppendFormat(CultureInfo.InvariantCulture, "<div class=\"editor-label\">{0}</div>\r\n", label);
}
builder.Append("<div class=\"editor-field\">");
}
builder.Append(templateHelper(html, propertyMetadata, propertyMetadata.PropertyName, null /* templateName */, DataBoundControlMode.Edit, null /* additionalViewData */));
if (!propertyMetadata.HideSurroundingHtml) {
builder.Append(" ");
builder.Append(html.ValidationMessage(propertyMetadata.PropertyName));
builder.Append("</div>\r\n");
}
}
return builder.ToString();
}
which clearly states that if the TemplateDepth > 1 just render a simple text.
As the above answer shows, this problem seems related to the framework limiting the depth of nesting it will consider.
One way to work around the problem is to use your own editor template. Create the partial view, Object.cshtml, in Views/Shared/EditorTemplates. Here's an example template taken from here:
#{
Func<ModelMetadata, bool> ShouldShow = metadata =>
metadata.ShowForEdit && !ViewData.TemplateInfo.Visited(metadata);
}
#if (ViewData.TemplateInfo.TemplateDepth > 5) {
if (Model == null) {
#ViewData.ModelMetadata.NullDisplayText
} else {
#ViewData.ModelMetadata.SimpleDisplayText
}
} else {
foreach (var prop in ViewData.ModelMetadata.Properties.Where(ShouldShow)) {
if (prop.HideSurroundingHtml) {
#Html.Editor(prop.PropertyName)
} else {
if (string.IsNullOrEmpty(Html.Label(prop.PropertyName).ToHtmlString())==false) {
<div class="editor-label">
#Html.Label(prop.PropertyName)
</div>
}
<div class="editor-field">
#Html.Editor(prop.PropertyName)
#Html.ValidationMessage(prop.PropertyName)
</div>
}
}
}
In the above example, you can set the maximum nesting depth by changing the 5 constant.

MVC3 Display a dropdown list from one datasource and save to another datasource

I'm getting back to an MVC3 project after a 3 month hiatus. I need to display a drop down list that pulls from Database A, but saves to Database B. The property I need to persist is the NAICS/SIC code. Right now I just provide the user a text box to key in freeform text. So, I have the mechanics of that down. But instead it should provide only a valid list of codes from a source database.
The tricky thing to is I'm using a custom model binder to generate my ViewModels on the fly, so I don't have a distinct .cshtml file to customize.
[Serializable]
public class Step4ViewModel : IStepViewModel
{
public Step4ViewModel()
{
}
//load naics codes from somewhere
[Display(Name = "Describe the nature of your business.")]
public String NatureOfBusiness { get; set; }
[Display(Name="NAICS/SIC CODE")]
public String BusinessTypeCode { get; set; }
Tricky ViewModel
#using Microsoft.Web.Mvc;
#using Tangible.Models;
#model Tangible.Models.WizardViewModel
#{
var currentStep = Model.Steps[Model.CurrentStepIndex];
var progress = ((Double)(Model.CurrentStepIndex) / Model.Steps.Count) * 100;
}
<script type="text/javascript">
$(function () {
$("#progressbar").progressbar({
value: #progress
});
});
</script>
<div id="progressbar" style="height:20px;">
<span style="position:absolute;line-height:1.2em; margin-left:10px;">Step #(Model.CurrentStepIndex + 1) out of #Model.Steps.Count</span>
</div>
#Html.ValidationSummary()
#using (Html.BeginForm())
{
#Html.Serialize("wizard", Model)
#Html.Hidden("StepType", Model.Steps[Model.CurrentStepIndex].GetType())
#Html.EditorFor(x => currentStep, null, "")
if (Model.CurrentStepIndex > 0)
{
<input type="submit" value="Previous" name="prev" />
}
if (Model.CurrentStepIndex < Model.Steps.Count - 1)
{
<input type="submit" value="Save & Continue" name="next" />
}
else
{
<input type="submit" value="Finish" name="finish" />
}
#*<input type="submit" value="Save" name="Save" />*#
}
Controller
[HttpPost]
public ActionResult Index([Deserialize] WizardViewModel wizard, IStepViewModel step)
{
wizard.Steps[wizard.CurrentStepIndex] = step;
if (ModelState.IsValid)
{
//Always save.
var obj = new dr405();
//wire up to domain model;
foreach (var s in wizard.Steps)
{
Mapper.Map(s,obj,s.GetType(), typeof(dr405));
}
using (var service = new DR405Service())
{
//Do something with a service here.
service.Save(db, obj);
}
if (!string.IsNullOrEmpty(Request["next"]))
{
wizard.CurrentStepIndex++;
}
else if (!string.IsNullOrEmpty(Request["prev"]))
{
wizard.CurrentStepIndex--;
}
else
{
return View("Upload", obj);
}
}
else if (!string.IsNullOrEmpty(Request["prev"]))
{
wizard.CurrentStepIndex--;
}
return View(wizard);
}
WizardViewModel
[Serializable]
public class WizardViewModel
{
public String AccountNumber { get; set; }
public int CurrentStepIndex { get; set; }
public Boolean IsInitialized { get { return _isInitialized; } }
public IList<IStepViewModel> Steps { get; set; }
private Boolean _isInitialized = false;
public void Initialize()
{
try
{
Steps = typeof(IStepViewModel)
.Assembly.GetTypes().Where(t => !t.IsAbstract && typeof(IStepViewModel).IsAssignableFrom(t)).Select(t => (IStepViewModel)Activator.CreateInstance(t)).ToList();
_isInitialized = true;
//rewrite this. get the profile and wire them up or something.
this.AccountNumber = Tangible.Profiles.DR405Profile.CurrentUser.TangiblePropertyId;
}
catch (Exception e)
{
_isInitialized = false;
}
}
}
You can specify a template for a specific property on your view model by adding the UIHint attribute to the field. Since your view calls EditorFor on the model it will use the template you specified with UIHint.
BusinessTypeDropdown.ascx - (placed in Views/Shared/EditorTemplates
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>
<% var businessTypes = ViewData["businessTypes"] as IEnumerable<string>; %>
<%= Html.DropDownListFor(m => m , new SelectList(businessTypes, Model))%>
In your View Model
[Serializable]
public class Step4ViewModel : IStepViewModel
{
public Step4ViewModel()
{
}
//load naics codes from somewhere
[Display(Name = "Describe the nature of your business.")]
public String NatureOfBusiness { get; set; }
[Display(Name="NAICS/SIC CODE")][UIHint("BusinessTypeDropdown")]
public String BusinessTypeCode { get; set; }
Then in your controller just set ViewData["businessTypes"] to your list of business types.
Without understanding your "tricky" view model code, it will be hard to make helpful suggestions.
However, there shouldn't be much problem here. You need to somehow create your dropdown list in yoru view, and populate it from data passed from your controller.
All the work happens in your controller. Populate your list or IEnumerable or whatever data source from your first database, then in your post handler save the selection it to your second database (the second part should not be much different from what you already have).

Resources