开发者

Two-way data binding in ASP.NET

Trying to use data binding between a list of objects and a data list control. What I want to do are

  1. create the list of objects
  2. have them bound to the controls
  3. change data in the UI
  4. have the changes in the ui bound to the list of objects
  5. on post back - have the list of objects with the new values from the ui

<body>
    <form id="form1" runat="server">
    <div>
        <asp:DataList ID="DataList1" runat="server" DataKeyField="ClassID" ViewStateMode="Enabled">
            <ItemTemplate>
                <asp:TextBox ID="txtValue1" runat="server" Text='<%# Bind("Value1") %>'开发者_如何学运维></asp:TextBox>
                <asp:TextBox ID="txtValue2" runat="server" Text='<%# Bind("Value2") %>'></asp:TextBox>
                <asp:TextBox ID="txtvalue3" runat="server" Text='<%# Bind("Value3") %>'></asp:TextBox>
            </ItemTemplate>
        </asp:DataList>
        <asp:Button ID="btnDoPostBack" runat="server" Text="Do Post Back" />
    </div>
    </form>
</body>

Option Explicit On
Option Strict On

Imports System.Diagnostics

Partial Class _Default
    Inherits System.Web.UI.Page

Dim Class1List As List(Of Class1)

Protected Sub Page_PreLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreLoad
    Dim txtValue1 As TextBox
    Dim txtValue2 As TextBox
    Dim txtValue3 As TextBox
    Dim ItemIndex As Integer = 0

    If Page.IsPostBack Then
        Class1List = CType(Session("Class1List"), List(Of Global.Class1))
        'Class1List = CType(DataList1.DataSource, List(Of Global.Class1))
        For Each myDataListItem As DataListItem In DataList1.Items
            txtValue1 = CType(myDataListItem.FindControl("txtValue1"), TextBox)
            Long.TryParse(txtValue1.Text, Class1List(ItemIndex).Value1)

            txtValue2 = CType(myDataListItem.FindControl("txtValue2"), TextBox)
            Integer.TryParse(txtValue2.Text, Class1List(ItemIndex).Value2)

            txtValue3 = CType(myDataListItem.FindControl("txtValue3"), TextBox)
            Class1List(ItemIndex).Value3 = txtValue3.Text

            ItemIndex += 1
        Next
    End If
End Sub

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Dim myClass1 As Class1

    If Not Page.IsPostBack Then
        Class1List = New List(Of Class1)
        myClass1 = New Class1
        Class1List.Add(myClass1)
        BindData()
    Else
        'Class1List = CType(DataList1.DataSource, List(Of Global.Class1))
        Debug.WriteLine("Page_Load, Value1 = " & Class1List(0).Value1.ToString())
        Debug.WriteLine("Page_Load, Value2 = " & Class1List(0).Value2.ToString())
        Debug.WriteLine("Page_Load, Value3 = " & Class1List(0).Value3)
    End If
End Sub

Protected Sub Page_Unload(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Unload
    Session("Class1List") = Class1List
End Sub

Sub BindData()
    DataList1.DataSource = Class1List
    DataList1.DataBind()
End Sub

Protected Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) Handles DataList1.ItemDataBound
    Dim myClass1 As Class1

    If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
        myClass1 = CType(e.Item.DataItem, Class1)
        Debug.WriteLine("DataList1_ItemDataBound, Value1 = " & myClass1.Value1.ToString())
        Debug.WriteLine("DataList1_ItemDataBound, Value2 = " & myClass1.Value2.ToString())
        Debug.WriteLine("DataList1_ItemDataBound, Value3 = " & myClass1.Value3)

    End If
End Sub

Protected Sub btnDoPostBack_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDoPostBack.Click
    Dim myRandom As New Random

    Class1List(0).Value1 = myRandom.Next(100)
    Class1List(0).Value2 = myRandom.Next(100)
    Class1List(0).Value3 = myRandom.Next(100).ToString()
    Debug.WriteLine("btnDoPostBack_Click, Value1 = " & Class1List(0).Value1.ToString())
    Debug.WriteLine("btnDoPostBack_Click, Value2 = " & Class1List(0).Value2.ToString())
    Debug.WriteLine("btnDoPostBack_Click, Value3 = " & Class1List(0).Value3)
    BindData()
End Sub
End Class

The Class Class1 is trivial:

Option Explicit On
Option Strict On

Imports Microsoft.VisualBasic

Public Class Class1
Private _ClassID As Long
Private _Value1 As Long
Private _Value2 As Integer
Private _value3 As String = String.Empty

Public Property ClassID As Long
    Get
        Return _ClassID
    End Get
    Set(ByVal value As Long)
        _ClassID = value
    End Set
End Property

Public Property Value1 As Long
    Get
        Return _Value1
    End Get
    Set(ByVal value As Long)
        _Value1 = value
    End Set
End Property

Public Property Value2 As Integer
    Get
        Return _Value2
    End Get
    Set(ByVal value As Integer)
        _Value2 = value
    End Set
End Property

Public Property Value3 As String
    Get
        Return _value3
    End Get
    Set(ByVal value As String)
        _value3 = value
    End Set
End Property
End Class

Update: I got the code behind above to do what I want it to do - I was thinking there was a better way?


You didn't show your databinding "Load" phase (the code which binds the data from the list to the controls)--so I assume the part you are unhappy with is the "Save" phase (the code in Page_PreLoad which binds the modified values from the controls back to the list), i.e. #4 in your list:

have the changes in the ui bound to the list of objects

It sounds like you want "two-way Data Binding": you want .NET to update your model as easily as it reads from your model. This is a common complaint. One solution is to subclass WebControl, but that's a mess.

You are already using the <%# Bind("...") %> syntax, so you have the right idea. That approach should work out-of-the-box with <asp:SqlDataSource>, but you want to update a custom class, so you need to use <asp:ObjectDataSource> instead. Use the approach in this article, except with ObjectDataSource instead of SqlDataSource.

But first you have to make your model (i.e., Class1) compatible with ObjectDataSource by marking it with [System.ComponentModel.DataObject] and designating the appropriate update method like this:

[System.ComponentModel.DataObjectMethodAttribute(
    System.ComponentModel.DataObjectMethodType.Update, true)]
public bool UpdateProduct(string productName, ...) {
    ...
}

This would allow you to use an ObjectDataSource on your webform and finally get nice 2-way databinding. Read the links to for full details.

Visual Studio offers various clunky ways of automating this, such as TableAdapters and the infamous Strongly-Typed DataSet (STD), but those don't help people like yourself who have their own object model. I don't recommend STDs anyway.

I was thinking there was a better way?

I don't think your current approach is bad. If you're worried about having tons of logic in your webforms, you would gain much more by using an MVC approach than worrying about binding sugar...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜