Как обновить модель, которая содержит список IMyInterface в MVC3 - PullRequest
0 голосов
/ 01 июля 2011

У меня есть такая модель:

        return new MyViewModel()
        {
            Name = "My View Model",

            Modules = new IRequireConfig[]
            {
                new FundraisingModule()
                {
                    Name = "Fundraising Module",
                    GeneralMessage = "Thanks for fundraising"
                },

                new DonationModule()
                {
                    Name = "Donation Module",
                    MinDonationAmount = 50
                }
            }
        };

Интерфейс IRequireConfig предоставляет строковое свойство DataEditor, которое представление использует для передачи в @ Html.EditorFor, например:

    @foreach (var module in Model.Modules)
    {
        <div>
            @Html.EditorFor(i => module, @module.DataEditor, @module.DataEditor)  //the second @module.DataEditor is used to prefix the editor fields
        </div>
    }

Когда я отправляю это обратно на мой контроллер, TryUpdateModel оставляет свойство Modules нулевым.Что в значительной степени ожидается, так как я не ожидал, что он узнает, к какому конкретному классу следует десериализоваться.

Поскольку у меня есть оригинальная модель, доступная, когда приходит сообщение, я могу перебрать Модули и получить их Тип, используя .GetType ().Кажется, что на данный момент у меня достаточно информации, чтобы TryUpdateModel попытался десериализовать модель, но проблема в том, что он использует вывод общего типа для управления десериализатором, поэтому он фактически не обновляет ни одно из свойств, кроме тех, которые определены винтерфейс.

Как я могу обновить мой массив модулей с их новыми значениями?

Если какая-то конкретная точка не ясна, пожалуйста, дайте мне знать, и я постараюсь уточнить

1 Ответ

1 голос
/ 01 июля 2011

Вы можете использовать пользовательскую модель переплета. Предполагая, что у вас есть следующие модели:

public interface IRequireConfig
{
    string Name { get; set; }
}

public class FundraisingModule : IRequireConfig
{
    public string Name { get; set; }
    public string GeneralMessage { get; set; }
}

public class DonationModule : IRequireConfig
{
    public string Name { get; set; }
    public decimal MinDonationAmount { get; set; }
}

public class MyViewModel
{
    public string Name { get; set; }
    public IRequireConfig[] Modules { get; set; }
}

Контроллер:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            Name = "My View Model",
            Modules = new IRequireConfig[]
            {
                new FundraisingModule()
                {
                    Name = "Fundraising Module",
                    GeneralMessage = "Thanks for fundraising"
                },
                new DonationModule()
                {
                    Name = "Donation Module",
                    MinDonationAmount = 50
                }
            }
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

Вид:

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Name)
    for (int i = 0; i < Model.Modules.Length; i++)
    {
        @Html.Hidden("Modules[" + i + "].Type", Model.Modules[i].GetType())
        @Html.EditorFor(x => x.Modules[i])
    }
    <input type="submit" value="OK" />
}

и, наконец, пользовательская модель переплета:

public class RequireConfigModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var typeParam = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Type");
        if (typeParam == null)
        {
            throw new Exception("Concrete type not specified");
        }
        var concreteType = Type.GetType(typeParam.AttemptedValue, true);
        var concreteInstance = Activator.CreateInstance(concreteType);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => concreteInstance, concreteType);
        return concreteInstance;
    }
}

который вы бы зарегистрировали в Application_Start:

ModelBinders.Binders.Add(typeof(IRequireConfig), new RequireConfigModelBinder());

Теперь, когда форма отправлена, тип будет отправлен, и механизм связывания модели сможет создать правильную реализацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...