MVC3 отображать выпадающий список из одного источника данных и сохранять в другом источнике данных

#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-обработчике сохраните его во второй базе данных (вторая часть не должна сильно отличаться от того, что у вас уже есть).