4

updatepanels を使用した部分的なポストバックについて少し理解しようとしていますが、多くのことが私を困惑させていますが、これには困惑しています。

UpdatePanel 内でタブを使用していますが、これはデータ入力アプリケーションであるため、コンテンツをユーザー コントロールに配置しているため、各タブには独自のユーザー コントロールがあります。さらに、各ユーザー コントロールにカスタム JavaScript を追加して、そのコントロール内のものに対して特定のクライアント側のものを処理します。

これを行うと、ユーザー コントロールの JavaScript が部分的なページのポストバックで起動しないことに気付きました。

これをシミュレートするために、VS2010 で非常に単純なアプリを作成しました (マスター ページで ScriptManager コントロールを備えたマスター ページを使用)。

デフォルト ページのコンテンツ パネルには次のものがあります。

<asp:UpdatePanel runat="server" UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
   <asp:Button runat="server" ID="Button1" Text="Partial postback" />
   <br />
   <asp:Panel runat="server" ID="panel"></asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>

次に、ユーザー コントロールを作成し、単純にプレーン テキストと JavaScript アラートを追加しました。

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="UC1.ascx.vb" Inherits="TestWebApp_VB.UC1" %>
This is user control 1
<script> alert('control 1'); </script>

次に、コンテンツ ページのページ読み込みイベントで、コントロールをパネルに読み込みます。

   Panel.Controls.Add(LoadControl("UC1.ascx"))

ボタンのクリック ハンドラーに加えて、コントロール (またはトグル時の別のコントロール) も読み込みます。

Button_Click
 Panel.Controls.Clear()
 Panel.Controls.Add(LoadControl("SomeControl.ascx"))

そのため、ページが最初に読み込まれるとアラートが発生しますが、ボタンをクリックしてページが部分的にポストバックされると、アラートは発生しません。

私はこれを一歩進めて、2 番目のユーザー コントロールを作成し、ボタンでコントロールの読み込みを切り替え、UpdatePanel の外側に通常のボタンを追加しました。完全なポストバックを実行すると、ロードされたユーザー コントロールの JavaScript が起動しますが、部分的なポストバックでは起動しません。

次に一歩前進し、コントロール内の JavaScript を関数に移動して、PageRequestManager または document.ready から関数を呼び出せるようにしました。

これで、2 つのコントロールにこのスクリプトが含まれるようになりました (アラートにはコントロールごとに異なるメッセージが含まれています)。

<script type="text/javascript">
  function userLoad() {
    alert("Identify control");
  }
</script>

したがって、これをコンテンツパネルの最後に追加しました

<script type="text/javascript">
   var prm = Sys.WebForms.PageRequestManager.getInstance().add_endRequest(userLoad);
</script>

さて、javascript はすべての部分的なポストバックで起動しますが、完全なポストバックによって最後に読み込まれたコントロールの javascript を起動します。

例:

  1. ページは最初に UserControl1 を読み込みます - UserControl1 のアラートが発生します (ここには示されていません - userLoad 関数は jquery document.ready で呼び出されています)
  2. ユーザーがボタンをクリック - UserControl2 をロードする必要があります
  3. UserControl2 は画面に読み込まれますが、UserControl1 のアラートが発生します

少し冗長で、申し訳ありませんが、これを説明する簡単な方法が見つかりませんでした。

- -編集 - -

私が試したことの 1 つで、Scotts の提案に取り組んでいます。各コントロールの JavaScript を個別のファイルに保存し、すべてを function UC1Load() {} のような名前の関数に入れます (気まぐれな場合は、その周りに名前空間を貼り付けることもできます)。スクリプト ファイルへの参照を追加します。を介したコンテンツページ

<script src='UC1.js'> 

次に、この関数を呼び出す起動スクリプトを登録します

 ScriptManager.RegisterStartupScript(ctrl, ctrl.GetType(), "UserJS", "UC1Load()", True)

これに関する最大の問題は、使用されることのない一連のスクリプトをダウンロードする必要があることです。そのため、最初にスクリプトをユーザー コントロールに配置していました。

4

3 に答える 3

2

あなたが取ることができる別の方法は、jQueryの.on()方法を使用することです。

セレクターが提供されている場合、イベント ハンドラーは委任されていると見なされます。イベントがバインドされた要素で直接発生した場合、ハンドラーは呼び出されませんが、セレクターに一致する子孫 (内部要素) に対してのみ呼び出されます。jQuery は、イベント ターゲットからハンドラーがアタッチされている要素 (つまり、最も内側の要素から最も外側の要素) までイベントをバブルし、セレクターに一致するそのパスに沿ったすべての要素に対してハンドラーを実行します。

イベント ハンドラーは、現在選択されている要素にのみバインドされます。これらは、コードが .on() を呼び出す時点でページに存在している必要があります。

...

委任されたイベントには、後でドキュメントに追加される子孫要素からのイベントを処理できるという利点があります。委任されたイベント ハンドラーがアタッチされた時点で存在することが保証されている要素を選択することで、委任されたイベントを使用して、イベント ハンドラーを頻繁にアタッチおよび削除する必要がなくなります。この要素は、Model-View-Controller デザインのビューのコンテナー要素、またはイベント ハンドラーがドキュメント内のすべてのバブリング イベントを監視する場合のドキュメントなどです。document 要素は、他の HTML をロードする前にドキュメントの head で使用できるため、ドキュメントの準備が整うのを待たずに安全にイベントをアタッチできます。

したがって、たとえば、次のように同じクラスを使用して、UserControls を div でラップできます。

ユーザーコントロール 1

<div class="userControl">
    <span>This is UserControl 1</span>
</div>

ユーザーコントロール 2

<div class="userControl">
    <span>This is UserControl 2</span>
</div>

次に、MasterPage の一番下の</body>タグの前に、jQuery 参照と jQuery スクリプトを含めます。私の例では、クリックさ<span />れたときに UserControl の内部の内容を出力します。<span />

jQuery

    <script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"></script>
    <script>
        $("div[id$=UpdatePanel1]")
            .on("click", "div.userControl span", function() { 
                alert($(this).html().trim()); 
            });
    </script>
</body>
</html>
于 2012-04-07T02:41:11.853 に答える
1

わかりました、独自のテスト Web サイトを作成し、いじくり回した後、次の作業を行いました。

TestControl1

<%@ Control Language="C#" 
            AutoEventWireup="true" 
            CodeFile="TestControl1.ascx.cs" 
            Inherits="Controls_TestControl1" %>

This is Test Control 1

TestControl2

<%@ Control Language="C#" 
            AutoEventWireup="true" 
            CodeFile="TestControl2.ascx.cs" 
            Inherits="Controls_TestControl2" %>

This is Test Control 2

10049777.aspx

<%@ Page Language="C#" 
         MasterPageFile="~/Site.master" 
         AutoEventWireup="true" 
         CodeFile="10049777.aspx.cs" 
         Inherits="_10049777" %>

<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="Server" />
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="Server">
    <asp:UpdatePanel ID="UpdatePanel1" runat="server" 
        UpdateMode="Conditional" 
        ChildrenAsTriggers="true">
        <ContentTemplate>
            <asp:Button ID="Button1" runat="server"
                Text="Partial postback" 
                OnClick="Button1_Click" />
            <br /><br />
            <asp:Panel runat="server" ID="Panel1" />
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

10049777.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        var TestControl1 = LoadControl("Controls\\TestControl1.ascx");

        Panel1.Controls.Add(TestControl1);
        ScriptManager.RegisterStartupScript(TestControl1, 
                                            TestControl1.GetType(), 
                                            "TestControl1Script", 
                                            "alert(\"control 1\");", 
                                            true);
    }
}

protected void Button1_Click(object sender, EventArgs e)
{
    var TestControl2 = LoadControl("Controls\\TestControl2.ascx");

    Panel1.Controls.Clear();
    Panel1.Controls.Add(TestControl2);

    ScriptManager.RegisterStartupScript(TestControl2, 
                                        TestControl2.GetType(), 
                                        "TestControl2Script", 
                                        "alert(\"control 2\");", 
                                        true);
}
于 2012-04-07T00:26:19.520 に答える
0

インライン スクリプトの問題について適切な説明が見つかりました

http://veskokolev.blogspot.com/2009/03/inline-scripts-in-updatepanel-doesnt.html

つまり、部分的なポストバックは、更新パネルの innerHtml を更新するため、html のブロブをストレート テキストとして認識し、html 内にスクリプト タグを登録しません。

だから私の最終的な解決策はこれでした。

各コントロールには、次のような名前の関数を含む独自の JavaScript ファイルがあります。

function controlNameLoad() { ..do your stuff }

コンテンツ パネル コード内 (読み込むコントロールを決定するための case ステートメント内)

dim ctrl = LoadControl("UCName.ascx")
panel.Controls.Add(ctrl)
ScriptManager.RegisterClientScriptInclude(ctrl, ctrl.GetType(), "UserJS", "UCName.js")
ScriptManager.RegisterStartupScript(ctrl, ctrl.GetType(), "UserJS", "controlNameLoad()", True)

これは私のテストプロジェクトで機能しており、実際のコードに実装できるかどうかは後でわかります。

于 2012-04-08T03:51:05.980 に答える