以编程方式在运行时向MVC模型添加属性

时间:2012-03-06 17:17:15

标签: asp.net-mvc-3

我正在尝试在运行应用程序时以编程方式在模型中创建属性。我试图按照Darin Dimitrov的帖子How to create controls dynamically in MVC 3 based on an XML file

来回答

我正在尝试将代码转换为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 Editor Template:

@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) 

Custom Model 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 个答案:

答案 0 :(得分:2)

您在主视图中缺少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调用,但您从未通过自定义模型绑定器使用的隐藏字段指定控件的类型。


更新:

我还修复了包含bug的原始模型绑定器,因为最好覆盖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