UserControl с UpdatePanel программно создать ScriptManager возможно?

Я хочу использовать UpdatePanel в своем UserControl. Проблема в том, что страница .aspx, на которой отбрасывается элемент управления, НЕ будет иметь ScriptManager. Мне нужно будет создать ScriptManager в UserControl. Однако если используется UserControl, скажем, дважды на странице, тогда размещение ScriptManager не сработает, потому что вы можете инициализировать ScriptManager только один раз.

В других UserControls, где мне нужен ScriptManager (я использовал расширения AJAX Toolkit Extensions), я смог использовать этот код:

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    Page.Init += new EventHandler(Page_Init);
}

void Page_Init(object sender, EventArgs e)
{
    if (Page.Form != null && ScriptManager.GetCurrent(Page) == null)
        Page.Form.Controls.AddAt(0, new ScriptManager());
}

..работала отлично, но не для случая UpdatePanel.

Обратите внимание: я НЕ использую мастер-страницы

(Другой подход, о котором я думал, но не могу понять, как это сделать, - это программно создать UserControl внутри UpdatePanel.)


person Darrell    schedule 09.07.2009    source источник
comment
Только сторона нет, код немного удваивается. Вы переопределяете метод OnInit и добавляете обработчик событий инициализации. Просто поместите код в Page_Init в переопределенный OnInit?   -  person Colin    schedule 09.07.2009


Ответы (5)


Я не думаю, что это возможно. Я пробовал это несколькими способами. Возможно, вам придется укусить пулю и разместить на своей странице диспетчер сценариев.

person Chris Mullins    schedule 09.07.2009

В чем причина того, что это не работает? Получаете ли вы исключение из UpdatePanel о том, что требуется ScriptManager? Вы используете System.Web.Extensions 1.0 или 3.5? Я говорю это, потому что в UpdatePanel в 3.5 было внесено изменение, которое заставляет его шаблон содержимого создавать экземпляр до OnInit, поэтому я не вижу очевидной причины, почему это не сработает. Если есть исключение, было бы полезно увидеть трассировку стека.

person InfinitiesLoop    schedule 16.07.2009

Я сталкиваюсь с той же проблемой. Проблема в том, что вам нужно добавить диспетчер сценариев до этапа OnInit - насколько я понимаю, это нужно сделать на этапе preinit. Вы можете увидеть это, добавив кучу переопределений - я обнаружил, что страница прошла через preinit ok, затем перешла к событию addedcontrol, и это было в (или сразу после, но этот момент имеет смысл), что «Вам нужен менеджер сценариев. "бросается. Я изо всех сил пытаюсь найти, как добавить обработчик событий к событию Page.PreInit из дочернего пользовательского элемента управления, поскольку WUC не имеют события PreInit. Даже конструктор WUC не срабатывает до этой точки, а в конструкторе объект страницы имеет значение NULL, поэтому вы не можете добавить его туда. Даже на этапе AddedControl WUC вы все еще не можете получить доступ к главной странице (ScriptManager oSCM = ScriptManager.GetCurrent (Page); возвращает null), поэтому вы не можете добавить диспетчер сценариев, если вы необходимо, прежде чем будет выдана ошибка.

/ edit: - Насколько я могу это видеть (и у меня не было ответа на это на форумах asp.net - сюрприз, сюрприз), WUC не начинает действовать в своих методах / событиях до тех пор, пока не пройдет стадия preinit родителя , так что есть 2 способа сделать это.

1) Как я думаю, я бы сделал это так, чтобы не помещать в конструктор какой-либо контент, который требует диспетчера сценариев, и помещать заполнители там, где это содержимое должно быть. Затем в загрузке wuc вы используете ScriptManager.GetCurrent, чтобы увидеть, есть ли он уже там, и затем создать его, если нет. Затем вы динамически добавляете контент, для которого требуется SCM. Что-то вроде этого:-


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

<asp:PlaceHolder ID="plcAJAX" runat="server" />
<asp:Label ID="lblGeneral" runat="server" Text="This is another label" />

----------------code behind---------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class wucTestExample : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ScriptManager oSCM = ScriptManager.GetCurrent(this.Page);
        if (oSCM == null)
        {
            oSCM = new ScriptManager();
            oSCM.ID = "scmAJAX";
            oSCM.EnablePartialRendering = true;
            this.plcAJAX.Controls.AddAt(0, oSCM);
        }

        UpdatePanel udpMain = new UpdatePanel();
        udpMain.ID = "udpMain";

        TextBox txtMain = new TextBox();
        txtMain.ID = "txtMain";
        // other attrbutes here

        Button btnPostback = new Button();
        btnPostback.ID = "btnPostback";
        btnPostback.Click += new EventHandler(btnPostback_Click);
        btnPostback.Text = "Partial Postback";

        Label lblPostback = new Label();
        lblPostback.ID = "lblPostback";
        lblPostback.Text = "initial postback";

        udpMain.ContentTemplateContainer.Controls.Add(txtMain);
        udpMain.ContentTemplateContainer.Controls.Add(btnPostback);
        udpMain.ContentTemplateContainer.Controls.Add(lblPostback);

        this.plcAJAX.Controls.Add(udpMain);
    }

    void btnPostback_Click(object sender, EventArgs e)
    {
        // implement button code here
        Label lblPostback = (Label)this.plcAJAX.FindControl("lblPostback");
        if (lblPostback != null)
        {
            lblPostback.Text = String.Format("WUC POstback at : {0}", DateTime.Now.ToLongTimeString());
        }
    }
}

затем используйте это так: -


<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="TestExampleNoSCM.aspx.cs" Inherits="TestExampleNoSCM" %>
<%@ Register Src="~/wucTestExample.ascx" TagName="wucTestExample" TagPrefix="ucTE" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
    <%--<asp:ScriptManager ID="scmAJAX" runat="server" />--%>
    <asp:Label ID="lblLoadTime" runat="server" />
    <ucTE:wucTestExample ID="wucTestExample" runat="server" />
</asp:Content>

----------------code behind---------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class TestExampleNoSCM : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        this.lblLoadTime.Text = String.Format("Page load at: {0}",DateTime.Now.ToLongTimeString());
    }
}

Поэтому, если вы прокомментируете или раскомментируете SCM на родительской странице, WUC все равно будет работать в любом случае.

2) Я видел другой вариант, когда требовалась панель обновления, и программист создал все элементы управления в дизайнере, а затем зациклил их при загрузке страницы (после создания SCM, если необходимо, и UDP и добавил все элементы управления на WUC UDP, прежде чем добавить это в заполнитель, но это кажется мне довольно опасным, поскольку кажется, что это двойное создание экземпляра элемента управления, и я думаю, что он может вернуться, чтобы укусить их за задницу ...

Обратной стороной метода 1 является то, что создание всего в вашей панели обновлений программным способом требует больше усилий, но если вы действительно хотите создать независимый WUC, это, похоже, ваша цена (и, надеюсь, WUC не должен быть таким сложным, так или иначе). Лично я думаю, что в своем приложении (поскольку WUC не будет использоваться вне его) я просто добавлю SCM там, где это необходимо, на главной странице.

Еще одно, последнее замечание, которое я хотел бы внести - я видел людей, говорящих «добавить его на главную страницу» - это кажется особенно плохой идеей, ИМХО, если только каждая страница в вашем приложении нужен SCM, поскольку он добавит совершенно новый уровень раздувания на ваши страницы, и это не кажется хорошей идеей, поскольку ASP.NET, похоже, уже имеет хороший уровень раздувания ...

person Mad Halfling    schedule 29.07.2009
comment
Похоже, ты знаешь, что делаешь! Пожалуйста, дайте мне знать, если найдете решение! - person Darrell; 30.07.2009
comment
одно предостережение с моим вышеупомянутым редактированием, добавление элементов управления программно потенциально добавляет уровень сложности в отношении состояния просмотра и т.д., поэтому моя работа по простому добавлению SCM к родительскому элементу (возможно, поместите комментарий в элемент управления, упоминающий это) может быть лучший вариант, если вам не нужен этот уровень или самостоятельность / переносимость. - person Mad Halfling; 06.08.2009

Вместо динамического добавления ScriptManager, если его нет на странице, просто сделайте противоположное: добавьте ScriptManager в свой ASCX и избавьтесь от него, если он уже есть на странице. Так...

protected override void OnInit(EventArgs e) {
    base.OnInit(e);
    AdjustScriptManager();
}

private void AdjustScriptManager() {
    if (ScriptManager.GetCurrent(Page) != null) {
        ScriptManager1 = null;
    }
}

ОБНОВИТЬ:

Нет, после дальнейшего тестирования это не сработает, поскольку ScriptManager1 = null не делает ничего полезного. Если есть способ сделать это (или удалить элемент управления страницей), прокомментируйте.

person kad81    schedule 16.01.2013

Решение: вы можете динамически добавить диспетчер сценариев в элемент управления пользователя, проверив, не содержит ли текущая страница ScriptManager. Вот как:)

В UserControl (ascx) html поместите это:

<asp:PlaceHolder ID="pHolder" runat="server" />

И в коде позади (ascx.cs):

    //insert Scriptmanager dynamically only IF it does not already exist
     private void createScriptManager(System.EventArgs e)
    {
        // the GetCurrent() method will return a ScriptManager from the Page
        if (System.Web.UI.AjaxScriptManager.GetCurrent(this.Page) == null)
        {
            System.Web.UI.AjaxScriptManager manager = new System.Web.UI.AjaxScriptManager();
            manager.EnablePartialRendering = true;
            pHolder.Controls.Add(manager);
        }
    }

    // call the above method from the usercontrol's OnInit
    override protected void OnInit(EventArgs e)
    {
        //
        // CODEGEN: This call is required by the ASP.NET Web Form Designer.
        //
        createScriptManager(e);
        base.OnInit(e);
    }

Иногда необходимо динамически определять ScriptManager. В моем случае я использую пользовательский элемент управления, который будет помещен на разные страницы, но некоторые из этих страниц уже содержат ScriptManager, а некоторые нет, поэтому как мой пользовательский элемент управления узнает, должен ли он определять свой собственный ScriptManager? Прелесть приведенного выше кода заключается в том, что пользовательский элемент управления добавляет диспетчер сценариев только в том случае, если его еще нет на странице.

Примечание. System.Web.UI.AjaxScriptManager можно заменить на System.Web.UI.ScriptManager, если вы используете старую версию Ajax.

person Spyder    schedule 26.11.2010
comment
Не работает. Когда пользовательский элемент управления содержит UpdatePanel, элемент управления даже не попадет в OnInit без ScriptManager на странице. И попытка сделать это в конструкторе пользовательского элемента управления не сработает, потому что Page будет иметь значение null. - person kad81; 16.01.2013