以编程方式向页面添加ScriptManager?

28

我正在开发一个WebPart(它将用于SharePoint环境,尽管它不使用对象模型),我希望在其中公开AJAX功能。由于环境的性质,直接向页面添加脚本管理器不是一种选择,因此必须以编程方式添加。我已经尝试在我的WebPart代码中向页面添加ScriptManager控件。

protected override void CreateChildControls()
{
    if (ScriptManager.GetCurrent(Page) == null)
    {
        ScriptManager sMgr = new ScriptManager();
        // Ensure the ScriptManager is the first control.
        Page.Form.Controls.AddAt(0, sMgr); 
    }
}

然而,当执行此代码时,我会收到以下错误消息:

"在 DataBind、Init、Load、PreRender 或 Unload 阶段期间无法修改控件集合。"

有没有另一种方法可以从 WebPart 向页面添加 ScriptManager,或者我需要将 ScriptManager 添加到每个将使用 WebPart 的页面(或主页面)中?

7个回答

41

我能够通过使用页面的 Init 事件使其正常工作:

protected override void OnInit(EventArgs e)
{
    Page.Init += delegate(object sender, EventArgs e_Init)
                 {
                     if (ScriptManager.GetCurrent(Page) == null)
                     {
                         ScriptManager sMgr = new ScriptManager();
                         Page.Form.Controls.AddAt(0, sMgr);
                     }
                 };
    base.OnInit(e);
}

3
如果你注意到了,我在检查页面上是否有 ScriptManager,然后才会添加一个。 - Kyle Trauberman
这个OnInit是控件的一个方法吗? - Shuo
6
无法与更新面板一起使用... 通过Page.Items[typeof(ScriptManager)] = newScriptManager正确设置脚本管理器的方法。 - controlflow
1
我在我的用户控件中有这个方法,但它仍然在抱怨,说:“ID为'upd'的控件需要页面上的ScriptManager。 ScriptManager必须出现在需要它的任何控件之前。” - M.R.
一旦我删除了委托并用包含在委托中的代码替换它,这对我起作用了。 - mezoid
显示剩余4条评论

7

我和你们所有人一样遇到了相同的问题。我正在创建一个自定义的ascx控件,并希望无需担心调用页面是否声明了scriptmanager。我通过在ascx控件本身中添加以下内容来解决这些问题。

添加到ascx页面中:

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

在更新面板本身中:oninit="updatePanel1_Init"

添加到ascx.cs文件中:

protected void updatePanel1_Init(object sender, EventArgs e)
{
     if (ScriptManager.GetCurrent(this.Page) == null)
     {
         ScriptManager sManager = new ScriptManager();
         sManager.ID = "sManager_" + DateTime.Now.Ticks;
         phScriptManager.Controls.AddAt(0, sManager);
     }
}

感谢本帖中帮我入门的所有人。

有什么特别的原因,为什么DateTime.Now.Ticks会被附加到ScriptManager的ID上? - Denis G. Labrecque
我刚在用户控件中使用了这个解决方案,它是我找到的唯一可行的解决方案!谢谢!但我确实不得不将sManager.ID = "sManager_" + DateTime.Now.Ticks;更改为sManager.ID = "ScriptManager1";以避免我的UpdatePanel出现奇怪的行为。 - user0474975

6
我已经完成了此项任务并且它有效。创建一个控件的占位符:

我已经完成了此项任务并且它有效。创建一个控件的占位符:

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

然后您可以在CreateChildControls中执行此操作:
ScriptManager aSM = new ScriptManager();
aSM.ID = "GridScriptManager";
WebGridPlaceholder.Controls.Add(aSM);

5

我在使用自定义ascx服务器控件时遇到了这个问题。 我尝试了许多解决方案,包括向控件的OnInit事件中添加脚本(在检查ScriptManager控件之后才执行),在控件的服务器标记内添加逻辑,以及在几乎每个其他事件中添加东西,但都不起作用。 最终,我构建了一个从ScriptManagerProxy继承的控件,然后使用ktrauberman的代码片段(稍加修改)来添加ScriptManager(如果需要):

  public class ProxiedScriptManager : ScriptManagerProxy
  {
    protected override void OnInit(EventArgs e)
    {
      //double check for script-manager, if one doesn't exist, 
      //then create one and add it to the page
      if (ScriptManager.GetCurrent(this.Page) == null)
      {
        ScriptManager sManager = new ScriptManager();
        sManager.ID = "sManager_" + DateTime.Now.Ticks;
        Controls.AddAt(0, sManager);
      }

      base.OnInit(e);
    }
  }

那对我来说就可以了。

3

这是我能找到的唯一方法,让我的更新面板在SharePoint 2007/2010兼容的Web部件中工作。我们使用了一个带有scriptmanager的2010主页,但没有一个2007主页。

.ascx

<asp:PlaceHolder ID="sMgr_place" runat="server" />
<asp:UpdatePanel runat="server" OnInit="updatePanel_Init"><ContentTemplate>
...
</ContentTemplate></asp:UpdatePanel>

.ascx.cs

public void updatePanel_Init(object sender, EventArgs e)
{
    if (ScriptManager.GetCurrent(Page) == null)
    {
        ScriptManager sMgr = new ScriptManager();
        sMgr.EnablePartialRendering = true;
        sMgr_place.Controls.Add(sMgr);
    }
}

1

我在包含更新面板的自定义Web控件(.cs)中使用了这段代码。

protected override void OnInit(EventArgs e)
{
    //...
    if (ScriptManager.GetCurrent(this.Page) == null)
    {
        ScriptManager scriptManager = new ScriptManager();
        scriptManager.ID = "scriptManager_" + DateTime.Now.Ticks;
        Controls.AddAt(0, scriptManager);
    }
    //...
}

0

我曾经遇到过类似的问题,发现最好的方法是在母版页中添加一个全局ScriptManager,然后在代码后台可以通过以下方式添加:

ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(virtualPath));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接