Двустороннее связывание данных в ASP.NET - PullRequest
3 голосов
/ 12 августа 2011

Попытка использовать привязку данных между списком объектов и элементом управления списком данных. Что я хочу сделать, это

  1. создать список объектов
  2. привязать их к элементам управления
  3. изменить данные в пользовательском интерфейсе
  4. имеют изменения в пользовательском интерфейсе, привязанном к списку объектов
  5. при отправке назад - есть список объектов с новыми значениями из пользовательского интерфейса

<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

Класс Class1 тривиален:

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

Обновление: я получил код выше, чтобы сделать то, что я хочу, - я думал, что есть лучший способ?

1 Ответ

3 голосов
/ 12 августа 2011

Вы не показывали свою фазу привязки данных «Загрузка» (код, который связывает данные из списка до элементов управления) - поэтому я предполагаю, что часть вас не устраиваетwith - это фаза «Сохранить» (код в Page_PreLoad, который связывает измененные значения с элементами управления обратно к списку), т.е. # 4 в вашем списке:

имеет изменения в пользовательском интерфейсе, привязанном к списку объектов

Звучит так, как будто вы хотите «двустороннее связывание данных»: вы хотите .NET для update ваша модель так же легко, как она читает из вашей модели.Это распространенная жалоба .Одним из решений является подкласс WebControl , но это беспорядок.

Вы уже используете синтаксис <%# Bind("...") %>, поэтому у вас есть правильная идея.Этот подход должен работать «из коробки» с <asp:SqlDataSource>, , но вы хотите обновить пользовательский класс, , поэтому вам нужно использовать <asp:ObjectDataSource>.Используйте подход из этой статьи , за исключением использования ObjectDataSource вместо SqlDataSource.

Но сначала вы должны сделать свою модель (т.е. Class1) совместимой с ObjectDataSource, пометив ее [System.ComponentModel.DataObject] и назначение соответствующего метода обновления следующим образом:

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

Это позволит вам использовать ObjectDataSource в вашей веб-форме и, наконец, получить хорошийДвусторонняя привязка данных.Для получения более подробной информации обратитесь к ссылкам.

Visual Studio предлагает различные неуклюжие способы автоматизации, такие как TableAdapters и печально известный строго типизированный набор данных (STD) ,но те не помогают таким людям, как вы, у которых есть своя объектная модель.В любом случае, я не рекомендую ЗППП.

Я думал, что есть лучший способ?

Не думаю, что ваш нынешний подход плох.Если вы беспокоитесь о наличии тонны логики в ваших веб-формах, вы бы получили гораздо больше пользы от подхода MVC , чем от связывания сахара ...

...