在页面中重用用户控件时,对子控件的引用不正确

Incorrect reference to child control when user control is reused in page

提问人:ClearlyClueless 提问时间:9/28/2023 更新时间:9/29/2023 访问量:21

问:

添加一个用户控件,该控件接受一些属性,并用于能够在应用程序中通常设置不同的配置值。

在某些情况下,这需要在同一页面上使用其中两个控件。我们将 Telerik ASP.Net 用于 Ajax 控件,但这不应特定于 Telerik 套件。代码如下,但控件的简单细分如下:

配置控制

  • “打开”按钮
  • 隐藏的容器窗口
    • 文本框
    • “提交”按钮

“打开”按钮显示在用户控件所在的页面上。单击此按钮不会触发回发,而是使用 javascript 打开容器窗口。

打开后,可以更新值,提交按钮会触发回发、提交更改并关闭窗口。

我的问题是: 当我将其中两个控件放在同一页面上以获得不同的值时,打开窗口的 JavaScript 位于控件内部,并在页面中重复,有时会引用和打开错误的窗口。我该如何解决这个问题?

    function OpenWindow(sender, args) {
        $find('<%= windowControlID.ClientID %>').show();
    }

控件将添加到父页面,如下所示:

<span style="display:block;">
    <uc:UpdateConfigurationValue id="configvalue1" runat="server" ConfigurationName="configValueName1" ConfigurationDescription="configValueDescription1" ConfigurationValueContext="configValueContext1" buttonWidth="100%" TelerikSkin="MetroTouch" FieldSecurityID="###" />
</span>
<span style="display:block;">
    <uc:UpdateConfigurationValue id="configValue2" runat="server" ConfigurationName="configValueName2" ConfigurationDescription="configValueDescription2" ConfigurationValueContext="configValueContext2" buttonWidth="100%" TelerikSkin="MetroTouch" FieldSecurity="###" />
</span>

用户控件标记:

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="UpdateConfigurationValue.ascx.vb" Inherits="JearLogistics.UpdateConfigurationValue" %>

<telerik:RadButton id="btnUpdateConfigurationValue" runat="server" AutoPostBack="false" OnClientClicked="btnUpdateConfigurationValue_OnClientClicked" />

<telerik:RadWindow ID="rwUpdateConfigurationValue" runat="server" Skin="MetroTouch" Behaviors="Default" VisibleStatusbar="false" ReloadOnShow="true" AutoSize="true" AutoSizeBehaviors="WidthProportional" >
    <ContentTemplate>
        <center>
            <div>
                <telerik:radlabel ID="lblConfigurationDescription" runat="server" Skin="MetroTouch"/>:
                <telerik:RadTextBox ID="txtConfigurationValue" runat="server" Skin="MetroTouch" />
                <telerik:RadLabel ID="lblConfigurationValueContext" runat="server" Skin="MetroTouch" />
            </div>
            <div>
                <telerik:RadButton ID="btnSubmitConfigurationChange" runat="server" AutoPostback="true" Skin="MetroTouch" Text="Submit" />
            </div>
        </center>
    </ContentTemplate>
</telerik:RadWindow>

<telerik:RadCodeBlock ID="codeBlockUpdateConfigurationValue" runat="server">
    <script type="text/javascript">
        function btnUpdateConfigurationValue_OnClientClicked(sender, args) {
            $find("<%= rwUpdateConfigurationValue.ClientID %>").show();
        }
    </script>
</telerik:RadCodeBlock>

用户控制代码隐藏

Imports Telerik.Web.UI
Public Class UpdateConfigurationValue
    Inherits System.Web.UI.UserControl

#Region "Generic Properties"
    Public Property ConfigurationName As String
    Public Property ConfigurationDescription As String
    Public Property ConfigurationValueContext As String

    Public Property ButtonWidth As Unit
    Public Property TelerikSkin As String
    Public Property FieldSecurityID As Long? = Nothing

    Private ReadOnly Property FieldSecurity As Dictionary(Of Integer, Boolean)
        ``` private security getters/setters
    End Property
    Private _FieldSecurity As Dictionary(Of Integer, Boolean)

#End Region

#Region "Post Update Deletgate"
    Public Delegate Sub OnSubmitButtonClicked()
    Public Property AfterSubmitButtonClicked As OnSubmitButtonClicked
#End Region

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not IsPostBack Then

            If FieldSecurityID IsNot Nothing AndAlso Not FieldSecurity(FieldSecurityID) Then
                btnUpdateConfigurationValue.Visible = False
                Exit Sub
            End If

            If Not ButtonWidth.IsEmpty Then btnUpdateConfigurationValue.Width = ButtonWidth
            If Not String.IsNullOrEmpty(TelerikSkin) Then btnUpdateConfigurationValue.Skin = TelerikSkin
            btnUpdateConfigurationValue.Text = $"Update {ConfigurationDescription}"

            Dim configItem As New TblConfiguration(ConfigurationName)
            lblConfigurationValueContext.Text = ConfigurationValueContext
            lblConfigurationDescription.Text = ConfigurationDescription

            txtConfigurationValue.Text = configItem.Value
        End If
    End Sub

    Private Sub SubmitConfigurationChange_Click(sender As RadButton, e As EventArgs) Handles btnSubmitConfigurationChange.Click
        Dim configItem As New TblConfiguration(ConfigurationName) With {
            .Value = txtConfigurationValue.Text
        }
        configItem.Update()

        Dim afterSubmitButtonClicked As OnSubmitButtonClicked = Me.AfterSubmitButtonClicked
        If afterSubmitButtonClicked IsNot Nothing Then afterSubmitButtonClicked()

    End Sub
End Class
JavaScript asp.net vb.net 用户控件

评论

0赞 Vasya 9/28/2023
听起来您有两个具有相同 ClientID 的控件。您可以通过查看生成页面的 html 来确认这一点。如果是这种情况,可以更改控件的 ClientIDMode 属性以生成唯一的 ClientID。
0赞 ClearlyClueless 9/29/2023
ClientID 是不同的。我已经确认使用 javascript 警报来输出它们。还更新了 clientIdMode 以尝试管理此问题,但 Telerik 有一个错误,当 clientIdMode 更改为 Static 或 Predictable 时,会导致 radwindow 无法显示内容。他们的文档说它已修复,但在最新版本中仍然是相同的行为。

答:

0赞 ClearlyClueless 9/29/2023 #1

在我自己研究这个问题时,最简单的解决方案是在按钮上启用回发,然后使用 responseScripts / 启动脚本来显示所需的窗口。这很有效,因为当与控件一起加载的 javascript 正在查看页面的内容时,子控件是用户控件范围内的唯一内容,而无需刻意单步执行页面。

下面的代码片段是从 Telerik 的文档中提取的,并保留为他们提供的通用代码:

Protected Sub Button1_Click(sender As Object, e As System.EventArgs) Handles Button1.Click
    'business logic goes here

    Dim script As String = "function f(){$find(""" + RadWindow1.ClientID + """).show(); Sys.Application.remove_load(f);}Sys.Application.add_load(f);"
    ScriptManager.RegisterStartupScript(Page, Page.GetType(), "key", script, True)
End Sub