让UpdatePanel支持文件上传(3):客户端组件

本文介绍了一个客户端组件UpdatePanelIFrameExecutor的设计与实现细节,包括如何处理异步刷新、执行请求和响应管理等核心功能。

我们继续编写客户端的部分。

  我们的UpdatePanelIFrameExecutor继承了WebRequestExecutor,因此需要实现许多方法和属性。但是我们事实上不用完整地实现所有的成员,因为客户端的异步刷信机制只会访问其中的一部分。以下是异步刷信过程中会使用的成员列表,我们必须正确地实现它们:

  • get_started: 表示一个Executor是否已经开始 了。
  • get_responseAvailable: 表示一个请求是否成功。
  • get_timedOut: 表示一个请求是否超时。
  • get_aborted: 表示一个请求是否被取消了。
  • get_responseData: 获得文本形式的Response Body。 
  • get_statusCode: 获得Response的状态代码
  • executeRequest: 执行一个请求。
  • abort: 停止正在运行的请求。

  UploadPanelIFrameExecutor依旧非常简单,只是定义了一些私有变量:

UpdatePanelIFrameExecutor构造函数

Jeffz.Web.UpdatePanelIFrameExecutor = function(sourceElement)
{
    Jeffz.Web.UpdatePanelIFrameExecutor.initializeBase(this);

    // for properties
    this._started = false;
    this._responseAvailable = false;
    this._timedOut = false;
    this._aborted = false;
    this._responseData = null;
    this._statusCode = null;
    
    // the element initiated the async postback
    this._sourceElement = sourceElement;
    // the form in the page.
    this._form = Sys.WebForms.PageRequestManager.getInstance()._form;
    // the handler to execute when the page in iframe loaded.
    this._iframeLoadCompleteHandler = Function.createDelegate(
        this, this._iframeLoadComplete);
}

  当executeRequest方法被调用时,我们会准备一个隐藏的iframe和所有的附加的隐藏输入元素,并将form的target指向iframe。当然,其他一些工作也是必须的,例如准备一个衡量超时的计时器:

executeRequest方法

executeRequest : function()
{
    // create an hidden iframe
    this._iframe = this._createIFrame();
    
    // all the additional hidden input elements
    this._addAdditionalHiddenElements();
    
    // point the form's target to the iframe
    this._form.target = this._iframe.id;
    this._form.encType = "multipart/form-data";        
    
    // set up the timeout counter.
    var timeout = this._webRequest.get_timeout();
    if (timeout > 0)
    {
        this._timer = window.setTimeout(
            Function.createDelegate(this, this._onTimeout), timeout);
    }
    
    this._started = true;
    
    // restore the status of the element after submitting the form
    setTimeout(Function.createDelegate(this, this._restoreElements), 0);

    // sumbit the form
    this._form.submit();
},

  建立一个隐藏得iframe元素很简单,但是我们该创建哪些附加的隐藏输入元素呢?自然我们表示“异步回送”的自定义标记是其中之一,那么剩下的还需要哪些呢?似乎我们只能通过阅读PageRequestManager的代码来找到问题的答案。还好,似乎阅读下面的代码并不困难:

_onFormSubmit方法

function Sys$WebForms$PageRequestManager$_onFormSubmit(evt)
{
    // ...
    
    // Construct the form body
    var formBody = new Sys.StringBuilder();
    formBody.append(this._scriptManagerID + '=' + this._postBackSettings.panelID + '&');

    var count = form.elements.length;
    for (var i = 0; i < count; i++)
    {
        // ...
        // Traverse the input elements to construct the form body
        // ...
    }

    if (if._additionalInput)
    {
        formBody.append(this._additionalInput);
        this._additionalInput = null;
    }

    var request = new Sys.Net.WebRequest();
    // ...
    // prepare the web request object
    // ...

    var handler = this._get_eventHandlerList().getHandler("initializeRequest");
    if (handler)    {
        var eventArgs = new Sys.WebForms.InitializeRequestEventArgs(
            request, this._postBackSettings.sourceElement);
        handler(this, eventArgs);
        continueSubmit = !eventArgs.get_cancel();
    }

    // ...

    this._request = request;
    request.invoke();

    // ...
}

  请注意红色部分的代码。可以发现有两种数据需要被添加为隐藏的输入元素。其一是ScriptManager相关的信息(第一部分的红色代码),其二则是变量“_additionalInput”的内容。我们很容易得到前者的值,但是后者的内容究竟是什么呢?我们继续阅读代码:

_onFormElementClick方法

function Sys$WebForms$PageRequestManager$_onFormElementClick(evt)
{
    var element = evt.target;
    if (element.disabled) {
        return;
    }

    // Check if the element that was clicked on should cause an async postback
    this._postBackSettings = this._getPostBackSettings(element, element.name);

    if (element.name)
    {
        if (element.tagName === 'INPUT')
        {
            var type = element.type;
            if (type === 'submit')
            {
                this._additionalInput = 
                    element.name + '=' + encodeURIComponent(element.value);
            }
            else if (type === 'image')
            {
                var x = evt.offsetX;
                var y = evt.offsetY;
                this._additionalInput = 
                    element.name + '.x=' + x + '&' + element.name + '.y=' + y;
            }
        }
        else if ((element.tagName === 'BUTTON') &&
            (element.name.length !== 0) && (element.type === 'submit'))
        {
            this._additionalInput = element.name + '=' + encodeURIComponent(element.value);
        }
    }
}

  _onFormElmentClick方法会在用户点击form中特定元素时执行。方法会提供变量“_additionalInput”的内容,然后紧接着,我们之前分析过的_onFormSubmit方法会被调用。现在我们就能够轻松地为form添加额外的隐藏输入元素了:

_addAdditionalHiddenElements方法

_addAdditionalHiddenElements : function()
{
    var prm = Sys.WebForms.PageRequestManager.getInstance();
    
    // clear the array of hidden input elements
    this._hiddens = [];
    
    // custom sign to indicate an async postback
    this._addHiddenElement("__AjaxFileUploading__", "__IsInAjaxFileUploading__");

    // the value related to the ScriptManager
    this._addHiddenElement(prm._scriptManagerID, prm._postBackSettings.panelID);
    
    // find the additional data
    var additionalInput = null;
    var element = this._sourceElement;
    if (element.name)
    {
        var requestBody = this.get_webRequest().get_body();
        
        if (element.tagName === 'INPUT')
        {
            var type = element.type;
            if (type === 'submit')
            {
                var index = requestBody.lastIndexOf("&" + element.name + "=");
                additionalInput = requestBody.substring(index + 1);
            }
            else if (type === 'image')
            {
                var index = requestBody.lastIndexOf("&" + element.name + ".x=");
                additionalInput = requestBody.substring(index + 1);
            }
        }
        else if ((element.tagName === 'BUTTON') &&
             (element.name.length !== 0) && (element.type === 'submit'))
        {
            var index = requestBody.lastIndexOf("&" + element.name + "=");
            additionalInput = requestBody.substring(index + 1);
        }
    }
    
    // parse the additional data
    if (additionalInput)
    {
        var inputArray = additionalInput.split("&");
        for (var i = 0; i < inputArray.length; i++)
        {
            var nameValue = inputArray[i].split("=");
            this._addHiddenElement(nameValue[0], decodeURIComponent(nameValue[1]));
        }
    }
},

_addHiddenElement : function(name, value)
{
    var hidden = document.createElement("input");
    hidden.name = name;
    hidden.value = value;
    hidden.type = "hidden";
    this._form.appendChild(hidden);

    Array.add(this._hiddens, hidden);
},

  除去附加的隐藏输入元素非常简单,不值一提。另外iframe在加载结束后的逻辑也很容易理解——不过解析内容的机制就另当别论了:

_iframeLoadComplete方法

_iframeLoadComplete : function()
{
    var iframe = this._iframe;
    delete this._iframe;
    
    var responseText = null;
    try
    {    
        // ...
        // retrieve the data we need
        // ...
        
        this._statusCode = 200;
        this._responseAvailable = true;
    }
    catch (e)
    {
        this._statusCode = 500;
        this._responseAvailable = false;
    }
    
    $removeHandler(iframe, "load", this._iframeLoadCompleteHandler);
    iframe.parentNode.removeChild(iframe);
    this._clearTimer();
    this.get_webRequest().completed(Sys.EventArgs.Empty);
},

  我们已经快完成我们的项目了。:)

点击这里下载整个项目

English Version

【论文复现】一种基于价格弹性矩阵的居民峰谷分时电价激励策略【需求响应】(Matlab代码实现)内容概要:本文介绍了一种基于价格弹性矩阵的居民峰谷分时电价激励策略,旨在通过需求响应机制优化电力系统的负荷分布。该研究利用Matlab进行代码实现,构建了居民用电行为与电价变动之间的价格弹性模型,通过分析不同时间段电价调整对用户用电习惯的影响,设计合理的峰谷电价方案,引导用户错峰用电,从而实现电网负荷的削峰填谷,提升电力系统运行效率与稳定性。文中详细阐述了价格弹性矩阵的构建方法、优化目标函数的设计以及求解算法的实现过程,并通过仿真验证了所提策略的有效性。; 适合人群:具备一定电力系统基础知识和Matlab编程能力,从事需求响应、电价机制研究或智能电网优化等相关领域的科研人员及研究生。; 使用场景及目标:①研究居民用电行为对电价变化的响应特性;②设计并仿真基于价格弹性矩阵的峰谷分时电价激励策略;③实现需求响应下的电力负荷优化调度;④为电力公司制定科学合理的电价政策提供理论支持和技术工具。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,深入理解价格弹性建模与优化求解过程,同时可参考文中方法拓展至其他需求响应场景,如工业用户、商业楼宇等,进一步提升研究的广度与深度。
针对TC275微控制器平台,基于AUTOSAR标准的引导加载程序实现方案 本方案详细阐述了一种专为英飞凌TC275系列微控制器设计的引导加载系统。该系统严格遵循汽车开放系统架构(AUTOSAR)规范进行开发,旨在实现可靠的应用程序刷写与启动管理功能。 核心设计严格遵循AUTOSAR分层软件架构。基础软件模块(BSW)的配置与管理完全符合标准要求,确保了与不同AUTOSAR兼容工具链及软件组件的无缝集成。引导加载程序本身作为独立的软件实体,实现了与上层应用软件的完全解耦,其功能涵盖启动阶段的硬件初始化、完整性校验、程序跳转逻辑以及通过指定通信接口(如CAN或以太网)接收和验证新软件数据包。 在具体实现层面,工程代码重点处理了TC275芯片特有的多核架构与内存映射机制。代码包含了对所有必要外设驱动(如Flash存储器驱动、通信控制器驱动)的初始化与抽象层封装,并设计了严谨的故障安全机制与回滚策略,以确保在软件更新过程中出现意外中断时,系统能够恢复到已知的稳定状态。整个引导流程的设计充分考虑了时序确定性、资源占用优化以及功能安全相关需求,为汽车电子控制单元的固件维护与升级提供了符合行业标准的底层支持。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值