Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
427 views
in Technique[技术] by (71.8m points)

c# - How to update a status label inside ajax request

I have this code :

<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>

When I click the button the animated gif shows... which is great, but the process takes over a minute and I would like to show the user (as long as the code is not complex) what is going on.

So I put a label next to the image, and in the code behind when I try and do :

lblStatus.Text = "Doing xyz";

It gives some sort of namespace issue. Any ideas how I can acheive this?

UPDATE : The error is "the type or namespace 'lblStatus' cannot be found".

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can't do this with the .net updatepanels, least I don't believe it to be easy. Though you can do it with 2 separate AJAX calls..

This example is using JQuery for the AJAX and the code-behind is in vb.net.

Essentially what you need to do is make your first call to begin the long process, then make a second call, repeatedly, using a second method to get the status of the long one.

AJAX

This is your main call to the long process. If needed, you will need to pass in the data to the method. Notice there is a processName. This should be a random string of sorts to ensure that you get the status of this process only. Other users will have a different random processName so you don't get confused status.

    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();
     }

Your second AJAX call will be to another method to get the progress. This will be called every XXX time by a timer method.

This is the TimerPoll function; which will fire every 3 seconds in this case

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

And finally, the GetProgress() function to, well, get the progress. We have to pass in the same processName used above, to get the process of this users call only

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();
                }
        });

    }

Now, in the back-end, you will have a couple of web methods that your AJAX communicates with. You will also need a shared/static object to hold all of the progress information, along with anything you want to pass back to the user.

In my case, i created a class which has its properties filled and passed back with every call to MyMainWorkerProcess. This looks a little like this.

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

I also have a shared property using this class, which looks like... ( this shared property is capable of holding multiple process progresses by multiple users - hence the dictionary. the key of the dictionary will be the process name. All progress data will be in the class ProcessData

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

My main worker function looks a little like this. Notice that we first make sure there isn't another processProgress with the same

<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

now all that is left is to call the progress method..All this is going to do is return the dictionary processData that has the same processName we set up earlier..

<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

And voila..

So to recap..

  1. Create 2 web methods - one to do the long process and one to return it's progress
  2. Create 2 separate calls to these web methods. The first is to the main worker, the second, which is repeated xx seconds, to one that will give the progress
  3. Output your messages to the user however you see fit...

Disclaimer... I haven't provided an answer this long on here before.. It might not follow the format people are used to seeing. Sorry if it all seems a little confusing :) I have copied most of the code from a running project so it should work.. though don't shoot me if there are a few typos :)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...