【问题标题】:How to update a status label inside ajax request如何更新ajax请求中的状态标签
【发布时间】:2012-10-15 14:43:48
【问题描述】:

我有这个代码:

<div style="padding: 0px 12px 12px 12px;">
    <asp:UpdatePanel runat="server" ID="Panel">
        <ContentTemplate>
            <asp:Button ID="btnGenerate" CssClass="button" Style="float: right" runat="server"
                Text="Go" OnClick="btnGenerate_Click" />
        </ContentTemplate>
    </asp:UpdatePanel>
</div>
<div>
    <asp:UpdateProgress runat="server" ID="PageUpdateProgress">
        <ProgressTemplate>
            <img src="ajax-loader.gif" />
            <asp:Label ID="lblStatus" runat="server" Text="Working..." CssClass="label" />
        </ProgressTemplate>
    </asp:UpdateProgress>
</div>

当我单击按钮时,动画 gif 会显示...这很棒,但是这个过程需要一分钟,我想向用户展示(只要代码不复杂)正在发生的事情。

所以我在图片旁边放了一个标签,在我尝试做的时候在后面的代码中:

lblStatus.Text = "Doing xyz";

它给出了某种命名空间问题。有什么想法可以实现吗?

更新: 错误是“找不到类型或命名空间'lblStatus'”。

【问题讨论】:

  • 确切的错误是什么?
  • 要在图片的位置显示标签文字?

标签: c# asp.net html ajax webforms


【解决方案1】:

如果你想动态改变使用下面的代码,

创建如下函数

function ChangeUpdateProgress(message)
{  
  document.getElementById('lblStatus').innerText=message;
}

调用事件的函数OnClick

<asp:LinkButton ID="btnUpdate" runat="server"Text="Update" OnClientClick="ChangeUpdateProgress('Please wait Updating....')" OnClick="btnUpdate_Click"></asp:LinkButton>

<asp:LinkButton ID="btnAdd" runat="server" OnClientClick="ChangeUpdateProgress('Please wait Adding....')" OnClick="btnAdd_Click"></asp:LinkButton>

希望这会有所帮助..

【讨论】:

  • 这不是第一次添加文本,而是在操作进行时从后面的代码更新它。
  • 根据您的要求编辑了我的帖子.. 试试这个
【解决方案2】:

代码会很复杂,因为你不能直接这样做。

ASP.NET AJAX 请求的体系结构是在请求完成之前它不会返回任何内容。这为您提供了一些不同的选择,包括:-

1) 将操作拆分为多个加载,自动重新部分发布以执行下一个并更新标签

2) 在服务的单独进程中运行操作(例如,使用 EXE)并在计时器上执行定期部分回发以与服务器上的 EXE 通信并获取当前状态并更新标签

3) 在 iframe 的页面中运行任务并使用 Response.Write 在关闭缓冲的情况下更新 iframe(或至少在每次状态更新后刷新)

【讨论】:

    【解决方案3】:

    要显示状态,您需要 2 个不同的 AJAX 调用,一个是当前和主要的调用,它实际上完成了工作,另一个只是检查当前状态返回一个非常简单的消息。

    //Changes the HTML like this
    <asp:UpdateProgress runat="server" ID="PageUpdateProgress">
        <ProgressTemplate>
            <span id="currentStatu"></span> <img src="ajax-loader.gif" />
        </ProgressTemplate>
    </asp:UpdateProgress>
    
    //Javascript
    setInterval(jQuery.get(page.aspx?status=1, function () { $("#currentStatu").text(data); } ), 500); // every 0.5 second.
    

    棘手的部分是如何从服务器端获取当前状态。如果您可以将其保留在 Session 中,这将是最简单的方法,此时 Request["status"] == "1" 只是将此 Session 作为文本返回,一切都已完成。

    另一方面,您也可以查询您的数据库以获取当前状态。

    希望对你有帮助。

    【讨论】:

    • 您不需要在会话中保持当前状态。因为脚本实际上正在运行,所以可以将状态存储在内存中并进行检索,就像我上面的示例一样。
    【解决方案4】:

    你不能用 .net 更新面板来做到这一点,至少我不认为这很容易。虽然你可以通过 2 个单独的 AJAX 调用来做到这一点..

    此示例使用 JQuery 进行 AJAX,代码隐藏在 vb.net 中。

    您需要做的基本上是进行第一次调用以开始漫长的过程,然后反复进行第二次调用,使用第二种方法来获取长期调用的状态。

    AJAX

    这是您对漫长过程的主要调用。如果需要,您需要将数据传递给该方法。注意有一个processName。这应该是一个随机字符串,以确保您仅获得此进程的状态。其他用户将有不同的随机 processName,因此您不会混淆状态。

        var processName = function GenerateProcessName() {
    
            var str = "";
            var alhpabet = "abcdefghijklmnopqrstuvwxyz";
            for (i = 1; i < 20; i++) {
                str += alhpabet.charAt(Math.floor(Math.random() * alhpabet.length + 1));
            }
            return str;
        }
    
    
        function StartMainProcess(){
        $j.ajax({
                type: "POST",
                url: "/MyWebservice.asmx/MyMainWorker",
                data: "{'processName' : '" + processName + "','someOtherData':'fooBar'}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (msg) {
                    if (msg.d) {                        
                        // do a final timerPoll - process checker will clear everything else
                        TimerPoll();
                    }
                }
            });
            TimerPoll();
         }
    

    您的第二次 AJAX 调用将使用另一种方法来获取进度。这将通过计时器方法每 XXX 次调用一次。

    这是 TimerPoll 函数;在这种情况下,它将每 3 秒触发一次

    function TimerPoll() {
            timer = setTimeout("GetProgress()", 3000)
        }
    

    最后,GetProgress() 函数用于获取进度。我们必须传入上面使用的相同的 processName,才能获取此用户调用的进程

    function GetProgress() {
            // make the ajax call
            $j.ajax({
                type: "POST",
                url: "/MyWebService.asmx/MyMainWorkerProgress",
                data: "{'processName' : '" + processName + "'}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (msg) {
    
                    // Evaulate result..
                    var process = msg.d
    
                    if (process.processComplete) {
                        // destroy the timer to stop polling for progress
                        clearTimeout(timer);
    
                // Do your final message to the user here.                      
    
                    } else {
    
                       // show the messages you have to the user.
                       // these will be in msg.d.messages
    
                        // poll timer for another trip
                        TimerPoll();
                    }
            });
    
        }
    

    现在,在后端,您将拥有几个与 AJAX 通信的 Web 方法。您还需要一个共享/静态对象来保存所有进度信息,以及您想要传回给用户的任何内容。

    在我的例子中,我创建了一个类,它的属性填充并在每次调用 MyMainWorkerProcess 时传回。这看起来有点像。

        Public Class ProcessData
            Public Property processComplete As Boolean
            Public Property messages As List(Of String) = New List(Of String)
        End Class
    

    我也有一个使用这个类的共享属性,它看起来像......(这个共享属性能够保存多个用户的多个进程进度 - 因此是字典。字典的键将是进程名称。所有进度数据将在 ProcessData 类中

    Private Shared processProgress As Dictionary(Of String, ProcessData) = New Dictionary(Of String, ProcessData)
    

    我的主要工作函数看起来有点像这样。请注意,我们首先确保没有另一个具有相同的 processProgress

    <WebMethod()> _
    <ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
    Public Function MyMainWorker(ByVal processName as string, ByVal SomeOtherData as string) as Boolean
    
            '' Create progress object - GUI outputs process to user
            '' If the same process name already exists - destroy it
            If (FileMaker.processProgress.ContainsKey(processName)) Then
                FileMaker.processProgress.Remove(processName)
            End If
    
            '' now create a new process
            dim processD as ProcessData = new ProcessData() with {.processComplete = false}
    
    
            '' Start doing your long process.
    
            '' While it's running and after whatever steps you choose you can add messages into the processData which will be output to the user when they call for the updates
             processD.messages.Add("I just started the process")
    
             processD.messages.Add("I just did step 1 of 20")
    
             processD.messages.Add("I just did step 2 of 20 etc etc")
    
             '' Once done, return true so that the AJAX call to this method knows we're done..
            return true
    
    End Function
    

    现在剩下的就是调用 progress 方法了。所有这一切都将返回字典 processData,它与我们之前设置的 processName 相同。

    <WebMethod()> _
        <ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
        Public Function MyMainWorkerProgress(ByVal processName As String) As ProcessData
    
            Dim serializer As New JavaScriptSerializer()
    
            If (FileMaker.processProgress.ContainsKey(processName)) Then
                Return processProgress.Item(processName)
            Else
                Return New ProcessData()
            End If
    
        End Function
    

    然后瞧……

    所以回顾一下..

    1. 创建 2 个 Web 方法 - 一个用于执行长流程,一个用于返回其进度
    2. 为这些 Web 方法创建 2 个单独的调用。第一个是给主要工作人员,第二个是重复 xx 秒,给一个会给出进度的人
    3. 以您认为合适的方式向用户输出您的消息...

    免责声明... 我之前没有在这里提供这么长时间的答案。它可能不符合人们习惯看到的格式。抱歉,如果这一切看起来有点混乱 :) 我已经从正在运行的项目中复制了大部分代码,所以它应该可以工作.. 如果有一些错别字,请不要开枪 :)

    【讨论】:

    • 支持 - 感谢您的努力,我相信它会对其他人有用,但对我来说我会通过。
    • 不用担心 :) 将进度信息传递给用户很痛苦,尽管就像我说的那样,我不认为使用 .net 更新面板更容易或不可能:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    • 1970-01-01
    相关资源
    最近更新 更多