【问题标题】:Programmatically adding properties to an MVC model at runtime在运行时以编程方式将属性添加到 MVC 模型
【发布时间】:2012-03-09 01:31:27
【问题描述】:

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

上关注 Darin Dimitrov 的回答

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

文本框编辑器模板:

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

自定义模型绑定器:

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

全球.asax:

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

当我运行应用程序时,自定义模型绑定器中的类型和名称变量似乎没有正确设置。

我做错了什么?

【问题讨论】:

    标签: asp.net-mvc-3


    【解决方案1】:

    您的主视图中缺少 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
    

    【讨论】:

    • 当我的模型来自数据库时,我现在无法创建它。创建一些控件的示例代码工作正常,但我不确定如何从数据库中完成。我试图将变量声明为 New ControlViewModel 但这不起作用,因为抽象类。知道如何将数据表映射到模型吗?
    • @cw_dev,我无法回答这个问题,因为您没有提供有关您的确切数据库架构和您使用的数据库访问技术的任何详细信息。可能值得开始一个新问题,因为这不再与 ASP.NET MVC 相关,而是更多地与 .NET 中的数据库访问相关。
    • 好的,谢谢。我确实设法通过做这样的事情让它工作。请注意确定它是否是最好的,但这确实有效。 Dim myList As New List(Of DataTitleControlsModel)() myList.Add(t) myList.Add(t2) myList.Add(t3) datatitlesmodel = New DataTitlesModel() With {.Controls = myList.ToArray}
    • 我看到 cmets 去掉了我的换行符,但希望你能看到我在做什么。这不是我遇到问题的 DB 位,我只是想弄清楚如何使用 .Add 行添加控件。
    • @cw_dev,您可以声明一个List(Of ControlViewModel) 变量,然后向其中添加元素:list.Add(t1) list.Add(t2) ... 其中t1t2 必须是ControlViewModel 的实例,或者更准确地说是其中之一派生类。填充列表后,您只需将其分配给视图模型的 Controls 属性即可。
    猜你喜欢
    • 1970-01-01
    • 2012-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多