Hello World
Spiga

编写组件,使用JavaScript更新UpdatePanel

2007-01-31 01:12 by 老赵, 8225 visits

众所周知,UpdatePanel是通过Trigger来更新的。被设定为Trigger的控件在PostBack之后会被客户端所截获,并且使用XMLHttpRequest对象发送内容,然后服务器端由ScriptManager配合,改变Page对象的输出,最后得到部分刷新的效果。但是有时候我们可能需要使用JavaScript来刷新UpdatePanel,这时候就不太方便了。

当然,我们又一个属于Workaround的方法,那就是使用JavaScript来模拟按钮的点击。我们往往会将一个按钮设为某个UpdatePanel的Trigger,然后在客户端模拟它的点击(我后面会提到,其实这是一个比较糟糕的做法,没有必要),使UpdatePanel进行更新。但是这样的做法实在太麻烦了些,也相当的不优雅。

现在我们就来编写一个组件解决这个问题。这个组件的名字叫做JavaScriptUpdater,似乎取得不怎么样——我一直不擅长取名。

 

首先来定一个需求吧

我们的目的,其实就是为了在客户端生成一个JavaScript代理,提供一个方法,调用它之后能够刷新页面。如果一个UpdatePanel的UpdateMode为Always,那么它一定会更新。如果需要更新UpdateMode为Conditional的UpdatePanel,就需要通过在页面中编写tag来设定哪些UpdatePanel也会被更新。我们需要尽可能的把编程工作变得最小。

不如我们先考虑使用方式,我们编写的这个JavaScriptUpdater在页面中可以这样使用:

<helper:JavaScriptUpdater runat="server" ID="Updater" MethodName="Refresh"
    ResolveUpdatePanel="OnResolveUpdatePanel" Enabled="True">
    <UpdatePanels>
        <helper:UpdatePanel UpdatePanelID="UpdatePanel1" />
        ...
    </UpdatePanels>
</helper:JavaScriptUpdater>

 

JavaScriptUpdater有一个简单属性MethodName,表明了在客户端生成代理方法的名字。再上例中该属性为Refresh,表明我们会调用UpdatePanels.Refresh()方法进行UpdatePanel更新。UpdatePanels是一个集合属性,可以指定哪些UpdateMode为Conditional的UpdatePanel一同进行更新。如果某个UpdatePanelID没有找到的话,就会调用ResolveUpdatePanel事件,让用户来指定一个UpdatePanel。还有一个Enabled属性,用于控制该JavaScriptUpdater是否生效。

一个页面里能够放置多个JavaScriptUpdater,这样可以生成多个JavaScript代理方法。这样的设定,应该已经足够用了。

 

实现JavaScriptUpdater

自然,我们先定义最简单的两个类,UpdatePanelHelper.UpdatePanel类,和ResolveUpdatePanelEventArgs类。由于实在简单,就直接贴一下代码了:

namespace UpdatePanelHelper
{
    public class UpdatePanel
    {
        private string _UpdatePanelID;
        public string UpdatePanelID
        {
            get { return _UpdatePanelID; }
            set { _UpdatePanelID = value; }
        }
    }
}
namespace UpdatePanelHelper
{
    public class ResolveUpdatePanelEventArgs : EventArgs
    {
        private string _ID = null;
        public string ID
        {
            get { return _ID; }
        }

        private System.Web.UI.UpdatePanel _UpdatePanel = null;
        public System.Web.UI.UpdatePanel UpdatePanel
        {
            get { return _UpdatePanel; }
            set { _UpdatePanel = value; }
        }

        public ResolveUpdatePanelEventArgs(string id)
        {
            this._ID = id;
        }
    }
}

 

然后开始考虑编写最关键的JavaScriptUpdater类。首先定义它的简单框架,如下:

namespace UpdatePanelHelper
{
    [PersistChildren(false)]
    [ParseChildren(true)]
    [NonVisualControl]
    public class JavaScriptUpdater : Control
    {
        private bool initialized = false;

        private bool _Enabled = true;
        public bool Enabled
        {
            get
            {
                return this._Enabled;
            }
            set
            {
                if (this.initialized)
                {
                    throw new InvalidOperationException(
"Cannot set the property after initialized."); } this._Enabled = value; } } private string _MethodName; public string MethodName { get { return this._MethodName; } set { if (this.initialized) { throw new InvalidOperationException(
"Cannot set the property after initialized."); } this._MethodName = value; } } public event EventHandler<ResolveUpdatePanelEventArgs> ResolveUpdatePanel; private List<UpdatePanel> _UpdatePanels = new List<UpdatePanel>(); [PersistenceMode(PersistenceMode.InnerProperty)] public List<UpdatePanel> UpdatePanels { get { return _UpdatePanels; } } ... } }

 

我们使用一个initialized变量来确保Enabled或MethodName属性只能在页面Init时进行修改。由于控件会在多个生命周期中进行操作,如果不做这样的限制,会让控制变得繁琐,容易出错。从下面的代码中会发现,我们会在响应页面的InitComplete事件时将initialized变量设为true。

我们在这里实现JavaScript更新UpdatePanel的做法,和传统的方法异曲同工,只是我们这里将动态添加按钮,并且在这里我们使用LinkButton。我们将响应Page对象的Load事件,添加那个作为Trigger的LinkButton。如下:

private string clientButtonId = null;

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

    this.Page.InitComplete += new EventHandler(Page_InitComplete);
}

private void Page_InitComplete(object sender, EventArgs e)
{
this.initialized = true;
if (this.Enabled) { this.Page.Load += new EventHandler(Page_Load); this.Page.PreRenderComplete += new EventHandler(Page_PreRenderComplete); } } private void Page_Load(object sender, EventArgs e) { LinkButton button = new LinkButton(); button.Text = "Update"; button.ID = this.ID + "Button"; button.Style[HtmlTextWriterStyle.Display] = "none"; button.Click += new EventHandler(OnTrigger); this.Page.Form.Controls.Add(button); this.clientButtonId = button.UniqueID; ScriptManager.GetCurrent(this.Page).RegisterAsyncPostBackControl(button); }

 

我们在页面的Page_InitComplete事件中判断Enabled属性是否为true(这时Enabled属性已经不能修改了),如果Enabled为ture,则响应页面的Load事件,用于动态添加一个LinkButton。请注意,我们并不会将它的Visible属性设为False,否则它的HTML将不会出现在页面上。我们应该将它Style的display设为none,这样它既能在页面结构中出现,也不会显示出来。在添加了这个LinkButton之后,将会保留它的ClientID,并且找出当前页面的ScriptManager,调用RegisterAsyncPostBackControl方法,将这个LinkButton注册为异步刷新页面的控件。

以前,我写给别人范例都是使用了一个Button作为Trigger,然后在客户端使用JavaScript对它进行点击。这其实不是很合理,比较好的做法其实使用LinkButton。要说明这个问题的原因,我们需要看一下LinkButton在页面中生成的HTML元素。很显然,这是个<a />,如下:

<a id="UpdaterButton" href="javascript:__doPostBack('UpdaterButton','')">Update</a>

 

请注意它的href,它表明了点击该元素会执行这个JavaScript代码。发现了不?我们何必模拟元素的点击,我们直接调用__doPostBack函数不就行了?Cool!于是我们现在也可以轻易得出,在响应页面的PreRenderComplete事件时需要注册的Script脚本了。如下:

private const string BasicScripts = 
@"if (!window.UpdatePanels) window.UpdatePanels = {};
UpdatePanels._createUpdateMethod = function(btnId)
{
    return function()
    {
        __doPostBack(btnId, '');
    }
}";

private const string RegisterMethodTemplate = 
    "\nUpdatePanels['{0}'] = UpdatePanels._createUpdateMethod('{1}');";
    
private void Page_PreRenderComplete(object sender, EventArgs e)
{
    this.Page.ClientScript.RegisterClientScriptBlock(
        this.GetType(),
        "BasicScripts",
        JavaScriptUpdater.BasicScripts,
        true);

    this.Page.ClientScript.RegisterClientScriptBlock(
        this.GetType(),
        this.clientButtonId,
        String.Format(JavaScriptUpdater.RegisterMethodTemplate, 
this.MethodName, this.clientButtonId), true); }

 

首先会注册一些基础脚本,我们会使用相同的Type和Key参数,这样保证了这段代码只会被注册一次。在注册每个代理方法的脚本时,就会使用该脚本的clientButtonId作为key,保证了每段脚本都会被注册成功。顺便一提,我们在这里直接使用了Page的ClientScriptManager来注册脚本,保证了在异步更新UpdatePanel时,不会将脚本发送到客户端去。

可能有朋友会出现疑惑,为什么我们需要在页面的PreRenderComplete事件中注册脚本呢?在页面的Load事件中一并注册了不可以吗?答案是,因为ScriptManager也是在这时候注册ASP.NET AJAX的基础脚本,我们现在这么做是为了保证了我们注册的脚本出现在ASP.NET AJAX的脚本之后。

哦,原来如此……等一下,是否发觉我们现在的脚本与ASP.NET AJAX的基础脚本无关?没错,事实上我们这里的确可以方法页面的Load事件中注册,我现在这么做似乎只是一个习惯——或者说是为ASP.NET AJAX编写组件的一个模式——响应页面的PreRenderComplete事件,用于注册所需的脚本。

大部分的工作已经完成了,我们只需要再响应那个LinkButton的Click事件即可。我们需要强制更新所有指定的UpdatePanel。代码如下,非常简单,就不多作解释了:

private void OnTrigger(object sender, EventArgs e)
{
    if (this.Enabled)
    {
        foreach (UpdatePanel panel in this.UpdatePanels)
        {
            System.Web.UI.UpdatePanel updatePanel = 
                this.FindUpdatePanel(panel.UpdatePanelID);

            if (updatePanel != null)
            {
                updatePanel.Update();
            }
        }
    }
}

private System.Web.UI.UpdatePanel FindUpdatePanel(string id)
{
    System.Web.UI.UpdatePanel result = null;

    if (id != null)
    {
        result = this.NamingContainer.FindControl(id)
            as System.Web.UI.UpdatePanel;
    }

    if (result == null)
    {
        ResolveUpdatePanelEventArgs e = new ResolveUpdatePanelEventArgs(id);
        this.OnResolveUpdatePanel(e);

        result = e.UpdatePanel;
    }

    return result;
}

private void OnResolveUpdatePanel(ResolveUpdatePanelEventArgs e)
{
    if (this.ResolveUpdatePanel != null)
    {
        this.ResolveUpdatePanel(this, e);
    }
}

 

使用JavaScriptUpdater

JavaScriptUpdater非常简单,只需一个最简单的例子,大家就可以明白它的使用方式:

<%@ Register Assembly="UpdatePanelHelper" Namespace="UpdatePanelHelper" TagPrefix="helper" %>

<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <%= DateTime.Now.ToString() %>
    </ContentTemplate>
</asp:UpdatePanel>

<helper:JavaScriptUpdater runat="server" ID="Updater" MethodName="Refresh">
    <UpdatePanels>
        <helper:UpdatePanel UpdatePanelID="UpdatePanel1" />
    </UpdatePanels>
</helper:JavaScriptUpdater>

<input type="button" onclick="UpdatePanels.Refresh()" value="Refresh" />

 

点击最下方定义的按钮时,会调用UpdatePanels.Refresh()方法,于是则会更新UpdatePanel1。请注意,UpdatePanel1的UpdateMode为Conditional,我们是通过在JavaScriptUpdater中指定它,用于强制对它进行更新。我们再看一下它生成的JavaScript代码和HTML就会更加清楚它的实现方式了。如下:

<script type="text/javascript">
    if (!window.UpdatePanels) window.UpdatePanels = {};
    
    UpdatePanels._createUpdateMethod = function(btnId)
    {
        return function()
        {
            __doPostBack(btnId, '');
        }
    }
    
    UpdatePanels['Refresh'] = UpdatePanels._createUpdateMethod('UpdaterButton');
</script>

...

<a id="UpdaterButton"
    href="javascript:__doPostBack('UpdaterButton','')"
    style="display:none;">Update</a>

 

点击这里下载源文件。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

50 条回复

  1. JesseZhao
    *.*.*.*
    链接

    JesseZhao 2007-01-31 02:09:00

    好文章,解决了很多问题啊。支持一下

  2. 老赵
    admin
    链接

    老赵 2007-01-31 02:19:00

    @JesseZhao
    也就……一个问题吧,呵呵

  3. Axel[未注册用户]
    *.*.*.*
    链接

    Axel[未注册用户] 2007-01-31 02:31:00

    是解决了很大的问题。

  4. 老赵
    admin
    链接

    老赵 2007-01-31 02:33:00

    @Axel
    谢谢支持。:)

  5. 浪子
    *.*.*.*
    链接

    浪子 2007-01-31 08:11:00

    @Jeffrey Zhao
    呵呵,Jeffrey跟前阶段写过的组件思路一样,每次模拟点击烦死了,就写了个UpdateProxy :)
    不过有些差别,我只为组件提供一个可以制定的客户端方法名称,和一个服务端事件,UpdatePanel指定这个组件参与异步,然后用户由自己定义的客户端方法自己call,触发服务端的事件,用起来感觉还是蛮方便的,就如一个button,但是不是通过鼠标点击,而是自己通过js调用,自己写的事件还可以克服以前button不能带回EventArg的缺点:)

  6. 阿一
    *.*.*.*
    链接

    阿一 2007-01-31 10:48:00

    不错,不错!

  7. Axel[未注册用户]
    *.*.*.*
    链接

    Axel[未注册用户] 2007-01-31 11:03:00

    @Jeffrey Zhao 兄
    ajax1.0对于webparts的支持一直是老问题。在updatepanel里放一下webpartzone,那个下拉菜单只能按一次,也就是做一次无刷新递交,第二次按就无效了。拖动也是一样,只能拖一次,拖第二次就没有用。
    因此至今还在用altas,是否做一下测试,指教一二。

  8. 老赵
    admin
    链接

    老赵 2007-01-31 11:37:00

    @浪子
    您的组件相当于可以再调用一个服务器端的方法,这样可以自己再写一些代码。我的目的是不要写任何代码,只是为了刷新。:)

  9. 老赵
    admin
    链接

    老赵 2007-01-31 11:37:00

    @阿一
    :)

  10. 老赵
    admin
    链接

    老赵 2007-01-31 11:38:00

    @Axel
    支持UpdatePanel的组件需要一定的条件,而目前的WebPartZone不支持UpdatePanel,如果Orcas要支持,可能需要重写这些控件。:(

  11. Axel[未注册用户]
    *.*.*.*
    链接

    Axel[未注册用户] 2007-01-31 11:51:00

    @Jeffrey Zhao
    感觉目前的webpartzone不支持updatepanel也有一定道理。因为webpartzone也是一个容器,并且一个页面不应只有一个webpartzone部件。这样必须每个webpartzone外面都加一个updatepanel或者在页面放一个updatepanel然后把webpartzone包进去。这样效率会有问题。webpartzone应该直接通过客户端去处理。我想ajax开发组应是出于这样的考虑吧,不知道自己动手去实现会有多少代价。

  12. 老赵
    admin
    链接

    老赵 2007-01-31 12:01:00

    @Axel
    其实性能倒也不会比一个完整的刷新差,因为我对WebPart没有很大研究,所以没有去关注解决它与ASP.NET AJAX的适应问题……:(

  13. 老赵
    admin
    链接

    老赵 2007-01-31 12:19:00

    @浪子
    您的建议也不错,那么我也添加一个,呵呵。反正不会影响使用,逻辑也简单:)

  14. chason[未注册用户]
    *.*.*.*
    链接

    chason[未注册用户] 2007-01-31 12:33:00

    看起来挺美

  15. Cat Chen
    *.*.*.*
    链接

    Cat Chen 2007-01-31 13:36:00

    官方设计这东西时怎么就不留下一个JavaScriptTrigger呢?好像获取Callback的Reference那样传递给客户端代码,也会很好用啊。

  16. 大剑师
    *.*.*.*
    链接

    大剑师 2007-01-31 15:10:00

    牛刀杀鸡啊,感觉为了优雅而优雅

  17. 老赵
    admin
    链接

    老赵 2007-01-31 21:56:00

    @chason
    不光优雅,其实很有用。:)

  18. 老赵
    admin
    链接

    老赵 2007-01-31 21:57:00

    @大剑师
    其实这个功能很重要,可读性提高是一方面,其实很常用。:)

  19. 老赵
    admin
    链接

    老赵 2007-01-31 21:57:00

    @Cat Chen
    是啊,其实官方如果提供这样方法其实是最理想的。

  20. yunhuasheng
    *.*.*.*
    链接

    yunhuasheng 2007-02-01 01:02:00

    挺好的!

  21. 老赵
    admin
    链接

    老赵 2007-02-01 01:08:00

    @yunhuasheng
    谢谢:)

  22. 怪怪[未注册用户]
    *.*.*.*
    链接

    怪怪[未注册用户] 2007-02-01 05:59:00

    @Axel
    @Jeffrey Zhao
    代价我知道 :)

    不知道你用WebParts来干嘛,我有段时间也用过WebParts系列,觉得微软有的话何必自己写(虽然好像功能多了点,一般来说多余功能太多的组件反而不应该选用的)。后来由于制肘太多,决心重写改变它的行为方式,发现这个控件系列如果在SP上绝对好用,但是一般的Web项目和门户上,它很多地方太沉重,也不合理。在我修改过程中,光Hack的方案代码就有近两千行(不涉及我自己的用户需求),涉及本来系统带的十来个类。

    这些类自己写其实并不困难,反而继承下来,让它既能按我的方式工作,又必须在原来WebParts的框架下浪费了非常多的功夫。我唯一的收获就是把ASP.NET 2.0页面生命周期和控件领域的相关知识又复习了一遍。你如果用这个,未来还会有需求的升级,有你受的。其实现在在AJAX 1.0下自己实现拖拽并不困难,你可以参考AjaxControlToolkit的那些例子修改一个~

    如果你的需求确实和WebParts系列的需求相接近,我给你几个建议:
    1.继承WebPartManager,实现ICallBackHandler接口(你可以看看随机帮助里的例子),实现一个接收参数的方法处理把数据送到持久层如果是原来的就是SqlPersonalizatonProvider我记得。也许或者实现一个独立的WebService来接收和处理。
    2.继承WebPartChrome什么的那个类,覆盖掉RenderVerbsInTitleBar方法,然后用你自己的方法渲染Menu和Menu的Verb。
    3.写点javascript,其作用是收集相关参数,回发给1,由服务器方法接收。

    上面的过程根据你需求的不同,可能不止重写这两个类。拖拽你用UpdatePanel解决了的话,这个工作量和难度还是可以接受的,只需要你比较浅的了解点html和javascript。需要注意的是你不用理会在你的需求中用不到的WebPart功能和行为模式,比如connection什么的,再比如你覆盖掉它原来渲染Menu和Verb的方法,就不必再管WebPartMenu和Verb的所有相关类,因为如果不追求结构和行为方式的相似,就永远用不着了。

    我原来就陷入这个怪圈,即继承的类应该实现所有父类的功能并有相同的行为模式,结果差点没吐血,微软自己写的类顾及的东西太多了,一个一个都打点好了可不容易;另外微软为了防止继承后更改出问题,很多地方都用的internal,你可以通过反射去调用,最重要的是保证你的代码和微软的代码存取的变量一致。

    如果需要拖动无刷新不想用UpdatePanel,你还需要用Ajax 1.0实现一个拖拽功能,然后跟原来的WebParts.js相结合,具体的你可以看Preview包里的实现,然后将拖拽后的postBack改为调用你自己写的一个CallBack的Javascript发回给1。

    其实AJAX小组不是你说的那些问题,是真的做不到。我相信他们水平比我高的多,但要保证在服务器端和原来的WebPart兼容,又要把所有功能重新实现,他们可以走一遍我重复过的路,但我可以在代码里大量的反射(你可以看看原来代码里很多地方做得多么的死,基本就不想让继承的类改变,因为如果改变一处就是一系列的地方都要改),他们可以写出这么个东西当产品发布吗 :P

    你要不着急等有空我整理一个你这种功能需求的WebPart系列控件上来....,最近有点忙可能没什么时间。看老赵这么无私贡献,我也被感染了,其实以前不喜欢管别人的事和交流的 :P

  23. 怪怪[未注册用户]
    *.*.*.*
    链接

    怪怪[未注册用户] 2007-02-01 06:02:00

    2 渲染得Menu,就是3的那些javascript。

    1 用ICallbackHandler最好,因为可以直接调用WebPartManager的WebPartPersonalization(好像是,不过也许得反射),以WebPartManager原有的形式把数据存入。

  24. 怪怪[未注册用户]
    *.*.*.*
    链接

    怪怪[未注册用户] 2007-02-01 06:09:00

    找到一些当时备份的文件,ICallBackHandler实现的方法大概是这样:

    public void RaiseCallbackEvent(string eventArgument)
    {
    string[] args = eventArgument.Split(new char[] { ':' });
    if (args.Length != 4)
    {
    return;
    }
    string wpPrefix = "WebPart_";
    if (args[1].StartsWith(wpPrefix))
    {
    args[1] = args[1].Substring(wpPrefix.Length);
    }
    int zoneIndex = int.Parse(args[3]);
    WebPart webPart = base.WebParts[args[1]];
    string zoneId = args[2];
    int IdIdx = zoneId.LastIndexOf('$');
    if (IdIdx > -1)
    {
    zoneId = zoneId.Substring(IdIdx + 1);
    }
    WebPartZoneBase zone = base.Zones[zoneId];
    if ((webPart == null) || (zone == null))
    {
    return;
    }
    switch (args[0].ToLower())
    {
    case "dragdrop":
    this.MoveWebPart(webPart, zone, zoneIndex);

    break;
    case "minimize":
    webPart.ChromeState = PartChromeState.Minimized;

    break;
    case "restore":
    webPart.ChromeState = PartChromeState.Normal;

    break;
    case "minimizeall":
    foreach (WebPart part2 in base.WebParts)
    {
    if (part2.AllowMinimize)
    {
    part2.ChromeState = PartChromeState.Minimized;
    }
    }

    break;
    case "restoreall":
    foreach (WebPart part3 in base.WebParts)
    {
    part3.ChromeState = PartChromeState.Normal;
    }

    break;
    case "delete":
    base.DeleteWebPart(webPart);
    break;

    case "close":
    base.CloseWebPart(webPart);
    break;
    }

    ((SilentWebPartPersonalization)base.Personalization).SaveInternal(base.WebParts);
    this.callbackResult = eventArgument;
    }

  25. 怪怪[未注册用户]
    *.*.*.*
    链接

    怪怪[未注册用户] 2007-02-01 06:16:00

    传回来的是id值,自己分析一下就可以。然后保存数据如下,即上面最后调用的那个类:

    public class SilentWebPartPersonalization : WebPartPersonalization
    {
    public SilentWebPartPersonalization(WebPartManager owner)
    : base(owner)
    {
    }

    internal void SaveInternal(WebPartCollection webParts)
    {
    if (base.IsModifiable)
    {
    this.ExtractPersonalizationState();
    foreach (WebPart part in webParts)
    {
    this.ExtractPersonalizationState(part);
    }
    this.Save();
    }
    }
    }


    别的太多了,估计你也用不着,看看这部分对你有没有帮助。javascript文件不知跑哪儿去了,但不是太难,就是组织参数而已。我回头看看能不能整理一个能用的版本...

  26. 数据绑定者
    *.*.*.*
    链接

    数据绑定者 2007-02-01 09:04:00

    支持老赵~

  27. 老赵
    admin
    链接

    老赵 2007-02-01 09:11:00

    @怪怪
    希望看到您的成果。:)

  28. 老赵
    admin
    链接

    老赵 2007-02-01 09:11:00

    @数据绑定者
    谢谢:)

  29. Anthan
    *.*.*.*
    链接

    Anthan 2007-02-01 10:29:00

    不错,以前实现延迟加载就用隐藏按钮,看了你写的,霍然开朗啊。
    真是高手!

  30. 老赵
    admin
    链接

    老赵 2007-02-01 10:47:00

    @Anthan
    谢谢支持,什么叫做“延迟加载”啊?

  31. Axel[未注册用户]
    *.*.*.*
    链接

    Axel[未注册用户] 2007-02-01 13:19:00

    @怪怪
    非常感谢您的帮助。其实这个问题困挠着很多人的。在asp.net社区有很多人提出类的问题。
    您的建议对我很有帮助。如果您能帮助做成控件真是太好了。我也会照您的思路研究一下。

  32. MK2
    *.*.*.*
    链接

    MK2 2007-03-24 20:32:00

    感谢老赵的辛勤劳动......

  33. 老赵
    admin
    链接

    老赵 2007-03-24 22:46:00

    @MK2
    谢谢您指出的错误。

  34. lv[未注册用户]
    *.*.*.*
    链接

    lv[未注册用户] 2007-05-13 17:22:00

    受益匪浅啊..不过还有个问题想请教下
    就是更新代码要写在哪里啊??
    我看源文件是
    <ContentTemplate>
    <%= DateTime.Now.ToString() %>
    </ContentTemplate>
    这样写的
    那假入我要对treeview或gridview进行一些插入数据的操作,这部分代码写在哪里啊??
    就是说原来<asp:AsyncPostBackTrigger>的EventName指向的方法里的代码要写在哪里啊??

  35. 老赵
    admin
    链接

    老赵 2007-05-13 22:44:00

    @lv
    我在这个控件中定义了OnUpdate事件,您可以使用它。
    不过我建议您可以不要使用我这个控件,因为它需要您对于UpdatePanel等有一定了解,否则误导您了就不好了。

  36. @zhang[未注册用户]
    *.*.*.*
    链接

    @zhang[未注册用户] 2007-05-16 16:14:00

    我的UpdatePanel里放置的是gridview我添加了新数据之后,更新Updatepanel同时如何重新加载新数据啊?也就是 在什么地方触发加载数据的方法啊?谢谢指教,请告知!

  37. 老赵
    admin
    链接

    老赵 2007-05-16 19:51:00

    @@zhang
    嗯?重新生成一下UpdatePanel的内容就可以了。

  38. Jz[未注册用户]
    *.*.*.*
    链接

    Jz[未注册用户] 2007-05-24 10:44:00

    这样做麻烦`

  39. Kane[未注册用户]
    *.*.*.*
    链接

    Kane[未注册用户] 2007-05-31 11:35:00

    这个helper支持多浏览器吗?似乎我试用了一下,IE是没有问题的,但是firefox和Safari似乎会出问题,提示服务器错误。

  40. yinix
    *.*.*.*
    链接

    yinix 2007-08-03 13:38:00

    赵老师:
    是不是一定要编写这样的组件来在客户端调用updatepanel使它进行更新呢?
    我用prototype.js写了这样的程序:
    function DeleteRole()
    {
    var DeleteRoleAjax=new Ajax.Request(
    url,
    {
    method:'post',
    parameters:
    {
    Action:'DeleteRole',
    RoleName:rolename
    },
    onComplete:ShowDeleteResult
    }
    );
    }

    function ShowDeleteResult(res)
    {
    $("btnUpdateRoleList").click();
    }
    这样子,在Ajax返回后,我想在客户端触发btnUpdateRoleList的click事件,在IE下面,页面没有完全刷新,达到效果,可是在FireFox下面不行。页面完全刷新。
    您怎么看?

  41. yinix
    *.*.*.*
    链接

    yinix 2007-08-03 15:13:00

    就是说有没有一种更轻量级的处理方法呢?

  42. 老赵
    admin
    链接

    老赵 2007-08-03 16:58:00

    @yinix
    你这个方法应该是可以的,能不能发一个最简单的出问题的例子给我呢?

  43. yinix
    *.*.*.*
    链接

    yinix 2007-08-03 18:25:00

    我先试试您的这个组件看看吧。看看有没有效果。刚好可以向您学习一下这方面的知识。

  44. yinix
    *.*.*.*
    链接

    yinix 2007-08-03 18:37:00

    赵老师:您的组件我刚用过了,FX和IE都测试了一下,没有出现问题。
    呵呵,我继续做我的项目了,马上要纳品了,有问题再请教您!
    谢谢赵老师!

  45. gya
    *.*.*.*
    链接

    gya 2008-10-06 17:01:00


    @Jeffrey Zhao
    @怪怪

    不知道赵老师最近研究了没有, 怪怪 的作品出来了没有,可以给我一份吗?都不知道这东西会给以后的项目带来什么恶果,我到底该不该用他?一个 拖动 问题我都很长时间都没有搞定,都开始怀疑自己了,把我的邮箱留下了,如果有能用的东西,共享一下把, guanyu1985@gmail.com


  46. huanglang[未注册用户]
    *.*.*.*
    链接

    huanglang[未注册用户] 2008-10-11 16:52:00

    请教老赵:
    我在iframe中用parent.UpdatePanels.Refresh()更新父窗体的UpdatePanel时,提示:Microsoft JScript 运行时错误: Sys.InvalidOperationException: 当 ScriptLoader 已经在加载脚本时,无法调用 ScriptLoader.loadScripts。

    请问如何解决?毕竟在iframe中更新还是很常见的。

  47. 郑毅添
    *.*.*.*
    链接

    郑毅添 2009-04-03 23:27:00

    谢谢赵老师!

  48. 牛牛博客
    *.*.*.*
    链接

    牛牛博客 2009-07-14 13:36:00

    谢谢

  49. 新昵称[未注册用户]
    *.*.*.*
    链接

    新昵称[未注册用户] 2009-07-17 10:49:00

    请问如果我想用这个在__doPostBack中传回一个参数,可以么?我试着修改了下,发现只要参数不为'',就会抛异常。
    谢谢了。

  50. 老赵
    admin
    链接

    老赵 2009-07-17 11:04:00

    其实说到底这种做法还是WebForm的UpdatePanel而已。
    因此,传递数据的方式还是通过页面上的hidden元素吧。

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我