困在Dynamic Controls,Viewstate和Postback上。简化示例

时间:2015-05-01 06:47:14

标签: asp.net vb.net postback viewstate

我一直在阅读帖子和链接,以及有关viewstate,statebag,回发和页面创建的文章。

我是一个非常体面的业余爱好者,但是这个人不是在沉没,有人能告诉我一个如何做到这一点的例子吗?

好的,这是我试图用这个例子做的事情

创建一个左列具有LinkBut​​tons

的表

单击每个linkBut​​ton时,它会在右列中打开一堆图像按钮

然后每个Imagebutton弹出一条消息

问题是图像按钮不会触发消息

这是前端:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="simple.aspx.vb" Inherits="simple" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>simple</title>
</head>
<body>
<form id="form1" runat="server">

<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>

<asp:Table id="MainTable" runat="server">
<asp:TableRow>

<asp:TableCell ID ="cell1" BackColor="LightBlue" />

<asp:TableCell ID ="cell2" BackColor="LightBlue" />

</asp:TableRow>
</asp:Table>

</form>
</body>
</html>

这是代码:

Partial Class simple
Inherits System.Web.UI.Page

Protected Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init

    Dim NewTableButton As LinkButton = New LinkButton
    NewTableButton.Text = "Text Created from 1st SQL Query"
    AddHandler NewTableButton.Click, AddressOf LoadContacts

    cell1.Controls.Add(NewTableButton)

End Sub

Protected Sub LoadContacts(sender As Object, e As System.EventArgs)

    Dim TextPassedfromLinkButton As String = sender.text.ToString

    Dim imgGear As New ImageButton
    imgGear.ImageUrl = "../graphics/gear.jpg"
    imgGear.AlternateText = "Text Created from 2nd SQL Query using the " _
 & TextPassedfromLinkButton & " as a query parameter"
    AddHandler imgGear.Click, AddressOf message

    cell2.Controls.Add(imgGear)

End Sub

Protected Sub message(ByVal sender As Object, ByVal e As System.EventArgs)

    Dim strText As String = sender.text.ToString
    Dim alertString As String = "alert('" & strText & "');"
    ScriptManager.RegisterStartupScript(Me, [GetType](), "showalert", alertString, True)

End Sub

End Class

单击应弹出消息的按钮

后,这是视图源
 <table id="MainTable">
 <tr>
 <td id="cell1" style="background-color:LightBlue;"><a href="javascript:__doPostBack(&#39;ctl03&#39;,&#39;&#39;)">Text Created from 1st SQL Query</a></td>
 <td id="cell2" style="background-color:LightBlue;"><input type="image" name="ctl04" src="../graphics/gear.jpg" alt="Text Created from 2nd SQL Query using the Text Created from 1st SQL Query as a query parameter" /></td>
 </tr>
 </table>

所以在此期间我让这个工作(更新10:49 est)

Protected Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init

    Dim NewTableButton As LinkButton = New LinkButton
    NewTableButton.Text = "Text Created from 1st SQL Query"
    'AddHandler NewTableButton.Click, AddressOf LoadContacts
    AddHandler NewTableButton.Click, Function() LoadContacts(NewTableButton.Text)

    cell1.Controls.Add(NewTableButton)

    If IsPostBack Then
        LoadContacts(NewTableButton.Text)
    End If

End Sub

Private Function LoadContacts(strText As String) As Integer

    Dim TextPassedfromLinkButton As String = strText

    Dim imgGear As New ImageButton
    imgGear.ID = "uniquename"
    EnableViewState = False
    imgGear.ImageUrl = "../graphics/gear.jpg"
    imgGear.AlternateText = "Text Created from 2nd SQL Query using the " & TextPassedfromLinkButton & " as a query parameter"
    AddHandler imgGear.Click, AddressOf message

    cell2.Controls.Add(imgGear)

    Return 0

End Function

唯一的问题是我得到2个相同的imgGears

duplicate buttons http://reinsmith.net/graphics/simple1.png message displayed http://reinsmith.net/graphics/simple2.png

2 个答案:

答案 0 :(得分:1)

这里的问题是你在另一个按钮的事件处理程序中实例化imgGear按钮

这样做似乎完全合乎逻辑,但是如果创建imgGear并且在页面生命周期中太晚将其添加到控制树中,则永远不会触发imgGear的事件处理程序,例如,在事件处理程序中或在OnPreRender期间。

使用标准.Net实践很难实现您的目标......我从未管理过它。您可能还注意到在事件处理程序期间添加的文本框通常不会在回发时保留其值,因为它在页面生命周期中添加得太晚了。

您确实需要在OnInit或CreateChildControls期间检测上下文,因为在该阶段中实例化并添加到控制树的按钮将触发其处理程序。

虽然我已经开发了一个工作......并且像大多数工作一样它并不漂亮......但它可以让你走出困境:

在OnInit期间,您可以判断您的按钮是否导致回发,如果它是成员变量。在构造函数中初始化NewTableButton ...然后你可以检测它是否在OnInit期间被点击...

   Private NewTableButton as Button

   Public Sub New()
        MyBase.New()
        NewTableButton = New LinkButton
        NewTableButton.Text = "Text Created from 1st SQL Query"
    End Sub

    Protected Overrides Sub OnInit(e As EventArgs)
        MyBase.OnInit(e)
        cell1.Controls.Add(NewTableButton)
        If Not IsNothing(Page.Request(NewTableButton.UniqueID)) Then
           ' Create and add imgGear Button
           LoadContacts
        End If
    End Sub

但是,在使用标准做法的OnInit期间,文本框/下拉值不可用...因此,您可能必须a)推迟读取它们直到OnPreRender,或b)使用Page.Request(控制。 UniqueID)在OnInit期间读取输入控件的值。

这是我用.Net网络开发的最大问题之一,它会引起头痛,我不喜欢解决问题......

我很想知道是否有替代方案,但这是我找到的唯一方法,可以实现您想要实现的目标。

答案 1 :(得分:0)

此处的问题是参考页面生命周期以及事件的连接方式。当您已经进入页面生命周期的事件处理程序阶段时,为新控件连接事件为时已晚。您需要在此过程的早期阶段执行此操作。

为了解决这个问题,我可以想到3种可能更符合Webforms的方法。

  1. 通过创建Repeater控件,DataGridView或类似方法并将Sql查询的结果绑定到该方法,使用数据驱动方法。此解决方案的一部分可能涉及编写一些原始的html / javascript以与转发器一起使用,与WebMethod一起使用,以使您的事件主要保持在客户端,并避免导致完全回发。鉴于我们已经知道你有一个SQL查询,这似乎是最自然的契合。
  2. 创建空的占位符控件,并将Visible属性设置为False,以获得所需的每个控件。然后在运行时将数据分配给现有控件,并仅为您实际使用的控件设置VisibleTrue。当您知道将有相对较少数量的项目,并且具有最大上限时,这通常是最佳选择。
  3. 开发一个自定义控件,将ImageButton / Message / Event概念封装到一个控件中。
  4. 此外,您对其他答案的评论表明,您可能需要考虑单独的页面来查看/编辑单个客户与查看所有客户(可能使用查询字符串参数)。在这个页面中,对于模态弹出窗口,我将其放入div,其中数据和支持弹出窗口的其他任何其他内容都是已经加载在页面的开头,并且只是使用javascript而不是服务器代码来改变页面DOM以显示或隐藏弹出窗口。