#asp.net-mvc-3 #data-binding #razor
#asp.net-mvc-3 #привязка данных #razor
Вопрос:
Я возвращаюсь к проекту MVC3 после 3-месячного перерыва. Мне нужно отобразить выпадающий список, который извлекается из базы данных A, но сохраняется в базе данных B. Свойство, которое мне нужно сохранить, — это код NAICS / SIC. Прямо сейчас я просто предоставляю пользователю текстовое поле для ввода текста произвольной формы. Итак, у меня есть механизм этого. Но вместо этого он должен предоставлять только действительный список кодов из исходной базы данных.
Сложность в том, что я использую пользовательскую модель binder для создания своих ViewModels «на лету», поэтому у меня нет отдельного файла .cshtml для настройки.
[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; }
Сложная 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 amp;amp; Continue" name="next" />
}
else
{
<input type="submit" value="Finish" name="finish" />
}
@*<input type="submit" value="Save" name="Save" />*@
}
Контроллер
[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 amp;amp; 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;
}
}
}
Комментарии:
1. Без подробной информации о ваших действиях контроллера GET и POST невозможно предоставить какие-либо полезные рекомендации. Пожалуйста, предоставьте более подробную информацию о том, что у вас есть на данный момент.
2. Почему ваша ViewModel выглядит как View? Мы можем видеть
WizardViewModel
?3. Этот код не был задуман мной (большая его часть взята из SO), я смог понять его достаточно хорошо, чтобы начать проект с нуля. Как я уже упоминал в своем посте, я был вне проекта уже 3 месяца и теперь не могу толком сказать, что к чему.
Ответ №1:
Вы можете указать шаблон для определенного свойства в вашей модели представления, добавив UIHint
атрибут в поле. Поскольку ваше представление вызывает EditorFor для модели, оно будет использовать указанный вами шаблон UIHint
.
businessstypedropdown.ascx — (помещается в 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))%>
В вашей модели представления
[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; }
Затем в вашем контроллере просто установите ViewData["businessTypes"]
свой список бизнес-типов.
Комментарии:
1. Я попробовал ваш ответ, и он сработал. Единственная проблема, с которой я столкнулся, заключалась в строке
Html.DropDownListFor(m => m , new SelectList(businessTypes, m))
, которую мне пришлось удалить самой последнейm
. Не могли бы вы объяснить, что я мог сделать неправильно?2. Второе переданное значение
new SelectList()
— это текущее выбранное значение. Что насчет этого не сработало?3. Ошибка, о которой сообщает VS read …
m
, не существует в текущем контексте.4. Моя ошибка,
SelectList
параметр не является частью лямбда, поэтомуm
не входит в область видимости. Попробуйтеnew SelectList(businessTypes, Model)
вместо этого.
Ответ №2:
Без понимания вашего «сложного» кода модели представления будет сложно вносить полезные предложения.
Однако здесь не должно быть особых проблем. Вам нужно каким-то образом создать свой выпадающий список в представлении yoru и заполнить его данными, переданными с вашего контроллера.
Вся работа происходит в вашем контроллере. Заполните свой список или IEnumerable или любой другой источник данных из вашей первой базы данных, затем в вашем post-обработчике сохраните его во второй базе данных (вторая часть не должна сильно отличаться от того, что у вас уже есть).