我正在尝试在运行应用程序时以编程方式在模型中创建属性。我试图按照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())
当我运行应用程序时,在自定义模型绑定器中,类型和名称变量似乎没有正确设置。
我可能做错了什么?
答案 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