Программное добавление свойств к модели MVC во время выполнения - PullRequest
1 голос
/ 06 марта 2012

Я пытаюсь создать свойства в моей модели программно при запуске приложения. Я попытался последовать ответу Дарина Димитрова на этот пост Как динамически создавать элементы управления в MVC 3 на основе XML-файла

Я пытаюсь преобразовать код в VB.NET. Пока у меня есть ...

Модель:

Public Class MyViewModel
    Public Property Controls As ControlViewModel()
End Class

Public MustInherit Class ControlViewModel
    Public MustOverride ReadOnly Property Type As String
    Public Property Visible As Boolean
    Public Property Label As String
    Public Property Name As String
End Class

Public Class TextBoxViewModel
    Inherits ControlViewModel
    Public Overrides ReadOnly Property Type As String
        Get
            Return "textbox"
        End Get
    End Property
    Public Property Value As String
End Class

Public Class CheckBoxViewModel
    Inherits ControlViewModel
    Public Overrides ReadOnly Property Type As String
        Get
            Return "checkbox"
        End Get
    End Property
    Public Property Value As Boolean
End Class

Контроллер:

Function Test() As ActionResult

    Dim model = New MyViewModel() With { _
    .Controls = New ControlViewModel() {New TextBoxViewModel() With { _
        .Visible = True, _
        .Label = "text label", _
        .Name = "TextBox1", _
        .Value = "Text appears here" _
    }, New CheckBoxViewModel() With { _
        .Visible = True, _
        .Label = "check label", _
        .Name = "CheckBox1", _
        .Value = True _
    }
    }}

    Return View("Test", model)

End Function

<httpPost()>
Function Test(model As MyViewModel) As ActionResult

    Return View("Test", model)

End Function

Вид:

@ModelType MyApp.DomainModel.MyTest.MyViewModel

@Code
Using Html.BeginForm()

Dim i As Integer
For i = 0 To Model.Controls.Length - 1
End Code
    <div> 
        @Html.EditorFor(Function(model) model.Controls(i)) 
    </div> 
@Code
Next
End Code

<input type="submit" value="OK" /> 

@Code
End Using
End Code

Шаблон редактора TextBox:

@modeltype MyApp.DomainModel.MyTest.TextBoxViewModel

@Html.LabelFor(Function(model) model.Value, Model.Label) 
@Html.TextBoxFor(Function(model) model.Value) 

Шаблон редактора флажков:

@modeltype MyApp.DomainModel.MyTest.CheckBoxViewModel

@Html.LabelFor(Function(model) model.Value, Model.Label) 
@Html.CheckBoxFor(Function(model) model.Value) 

Пользовательская модель Binder:

Public Class ControlModelBinder
    Inherits DefaultModelBinder

    Public Overrides Function BindModel(controllerContext As ControllerContext, bindingContext As ModelBindingContext) As Object
        Dim type = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Type")
        Dim name = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Name")
        Dim value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Value")

        If type IsNot Nothing AndAlso value IsNot Nothing Then
            Select Case type.AttemptedValue
                Case "textbox"
                    Return New TextBoxViewModel() With { _
                          .Name = name.AttemptedValue, _
                          .Value = value.AttemptedValue _
                        }
                Case "checkbox"
                    Return New CheckBoxViewModel() With { _
                          .Name = name.AttemptedValue, _
                          .Value = Boolean.Parse(value.AttemptedValue.Split(","c).First()) _
                        }
            End Select
        End If

        Throw New NotImplementedException()

    End Function
End Class

Global.asax:

ModelBinders.Binders.Add(GetType(MyTest.ControlViewModel), New MyTest.ControlModelBinder())

Когда я запускаю приложение, в пользовательском связывателе модели переменная типа и имени, кажется, установлена ​​неправильно.

Что я мог делать не так?

1 Ответ

2 голосов
/ 06 марта 2012

Вам не хватает 2 скрытых полей на главном экране:

@ModelType MyApp.DomainModel.MyTest.MyViewModel

@Using Html.BeginForm()
    For i = 0 To Model.Controls.Length - 1
        @<div> 
            @Html.HiddenFor(Function(model) model.Controls(i).Type) 
            @Html.HiddenFor(Function(model) model.Controls(i).Name) 
            @Html.EditorFor(Function(model) model.Controls(i)) 
        </div> 
    Next
    @<input type="submit" value="OK" /> 
End Using

В вашем коде у вас есть только один вызов EditorFor для свойства Controls, но вы никогда не указываете тип элемента управлениячерез скрытое поле, которое используется пользовательским связывателем модели.


ОБНОВЛЕНИЕ:

Я также исправил исходный связыватель модели, который содержал ошибку, поскольку лучше переопределить CreateModelметод вместо BindModel:

Public Class ControlModelBinder
Inherits DefaultModelBinder
Protected Overrides Function CreateModel(controllerContext As ControllerContext, bindingContext As ModelBindingContext, modelType As Type) As Object
    Dim type = bindingContext.ValueProvider.GetValue(Convert.ToString(bindingContext.ModelName) & ".Type")
    If type Is Nothing Then
        Throw New Exception("The type must be specified")
    End If

    Dim model As Object = Nothing
    Select Case type.AttemptedValue
        Case "textbox"
            If True Then
                model = New TextBoxViewModel()
                Exit Select
            End If
        Case "checkbox"
            If True Then
                model = New CheckBoxViewModel()
                Exit Select
            End If
        Case "ddl"
            If True Then
                model = New DropDownListViewModel()
                Exit Select
            End If
        Case Else
            If True Then
                Throw New NotImplementedException()
            End If
    End Select

    bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(Function() model, model.[GetType]())
    Return model
End Function
End Class
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...