asp.net 如何在单击按钮后异步多次更新标签

56lgkhnf  于 2024-01-09  发布在  .NET
关注(0)|答案(1)|浏览(135)

我有一个基于.Net Framework 4.8构建的网站。我有一个按钮,当点击它时,它会按顺序对服务器进行远程调用同步。可能有数千个操作,每个操作可能需要几秒钟才能响应。
因此,我希望在页面上显示当前进度的标签,如“1/1000 actions performed”和“Current Action: Boot ”。
下面是一个模拟场景的示例代码:

<asp:Button ID="StartButton_Click" OnClick="StartButton_Click" Text="Start" runat="server"/>
<asp:UpdatePanel ID="ProgressUpdatePanel" runat="server">
    <ContentTemplate>
        <asp:Label ID="ProgressLabel" runat="server"></asp:Label>
    </ContentTemplate>
    <Triggers>
    </Triggers>
</asp:UpdatePanel>

字符串
以及模拟远程调用的处理程序:

protected void StartButton_Click(object sender, EventArgs e)
{
    List<string> actions = (List<string>)Enumerable.Repeat("0", 100);
    processItem(actions, 0);
}

private void processItem(List<string> items, int index)
{
    if(index >= items.Count)
    {
        return;
    }
    else
    {
        System.Threading.Thread.Sleep(3000);
        /* Can't update ProgressLabel.Text here,
           because I can't update anything before the page is returned to the client*/
        processItem(items, index + 1);
    }
}


我最接近的方法是使用TimerControl来执行PostBacks来读取进度并更新标签,但这感觉像是一种变通方法,我想知道是否有更好的方法。

<asp:Button ID="StartButton_Click" OnClick="StartButton_Click" Text="Start" runat="server"/>
<asp:Timer ID="Timer1" OnTick="Timer1_Tick" runat="server" Interval="1000" Enabled="false" />
<asp:UpdatePanel ID="ProgressUpdatePanel" runat="server">
    <ContentTemplate>
        <asp:Label ID="ProgressLabel" runat="server"></asp:Label>
    </ContentTemplate>
    <Triggers>
        <asp:AsyncPostBackTrigger ControlID="Timer1" />
    </Triggers>
</asp:UpdatePanel>
static currentCount = 0; //updated by processItem

protected void Timer1_Tick(object sender, EventArgs e)
{
    ProgressLabel.Text = $"{currentCount}/{totalCount} actions performed";
}

的字符串
我还尝试在ViewState中强制回发和保存状态,但这需要在客户端自动触发回发,这感觉真的不对。

m1m5dgzv

m1m5dgzv1#

首先,对于20,或者也许100?然后罚款。然而,你的帖子建议在1000+范围。这是一个非常但超越大规模非常不同的挑战和计算机问题。
请记住,谷歌,微软和更多的人在招聘面试中问上述类型的问题(问题的类“多大”,“多远”,“多长时间”).这样的问题的原因是有一个巨大的差异,比如说一些进度系统在网页上的20甚至50个项目.但是,1000+是一个全新的不同类型的问题和挑战.
一个网站不太可能运行和控制一个有1000多件事情要做的进程。一个网站可能会“监视”这样一个进程已经进展了多少,但不负责运行这样的代码.

  • 这不再是一个网站类型的应用程序。*

我们必须区分“真实的时间”更新和监控,因为它相当于让一些Web服务器代码调用+运行1000个不同的进程。
这很像我们每5秒钟从某个机器设备获取并显示一个温度阅读,甚至是一个外部温度计值以供显示的区别。
当一个人开始谈论1000多个进程时,那么我们不可能知道,不知道,也不会知道每个进程运行所需的时间。一个网站不足以可靠地负责调用那么多例程。然而,对这种处理进行某种轮询是有意义的。
那么,假设40或75个手术?那么当然,我们可以基于网络来做。
然而,在我们发布一些适用于简单用例的简单代码之前?
如果您正在寻找一个真实的时间更新?
那么你会做得很好,采用SignalR,因为这是专为这类任务。
SignalR向服务器证明与浏览器的真实的Web Socket连接。因此,对于“与朋友聊天”类型的应用程序,两者都可以在网络浏览器中键入,并且两者都可以真实的看到彼此正在键入的文本。
因此,SignalR技术也适用于工厂车间的监控设备,甚至是简单的外部温度显示。因此,对于这种类型的真实的时间更新 *(以及超出正常情况的疯狂情况,您有1000多个进程要监控 *)?
您可以从这里开始使用SignalR(它是为这些真实的时间更新和进程监控类型的问题而设计的)。SignalR将允许您的服务器端代码甚至在循环中将状态更新到浏览器中。
因此,对于您巨大的,巨大的,超越疯狂的需求,以跟踪1000+处理事件,那么SignalR是要走的路:
链接:
https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/
然而,对于我们这些凡人来说,一个简单的处理和更新循环?
说这个标记:

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>

             <asp:Button ID="cmdProcess" runat="server" Text="to hide button" ClientIDMode="Static"
                  OnClick="cmdProcess_Click" style="display:none"  />

                <asp:Button ID="Button1" runat="server" Text="Start the Reactor"                        
                    ClientIDMode="Static" CssClass="btn"
                    OnClientClick="startprocessor('Processing',1,18);return false"
                    />
                <br />
                    <asp:HiddenField ID="pStep" runat="server" ClientIDMode="Static" />
                    <asp:HiddenField ID="pSteps" runat="server" ClientIDMode="Static" />

                <div id ="MessageArea" style="display:none">

                    <style>
                        .ui-progressbar-value {background: lightskyblue;}
                    </style>

                    <div id="pbar" 
                        style="width:400px">
                    </div>

                    <asp:Label ID="lblmsg" runat="server" Text="" ClientIDMode="Static"></asp:Label>
                    <br />
                </div>
            </ContentTemplate>
        </asp:UpdatePanel>
               
        <script>

            var prm = Sys.WebForms.PageRequestManager.getInstance();
            prm.add_endRequest(EndRequestH);

            function EndRequestH(sender, args) {
                // code here
                lbl = $('#lblmsg')
                if (lbl.text() !== "") {
                    // more processing required
                    $('#MessageArea').show()
                    iStep = $('#pStep').val()
                    iSteps = $('#pSteps').val()
                    lbl.text("(" + iStep + "/" + iSteps + ") " + lbl.text())
                    $('#pbar').progressbar({ value: iStep / iSteps * 100 });
                    $('#cmdProcess').click()
                }
            }

            function startprocessor(sMsg, iStep, iSteps) {
                var mymsg = "(1/" + iSteps + ") " + sMsg
                $('#lblmsg').text(sMsg)
                $('#pStep').val(iStep)
                $('#pSteps').val(iSteps)
                EndRequestH()
            }
        </script>

字符串
所以,我们有一个更新面板,设置处理步骤,点击一个按钮。后面的代码运行,然后完成后,客户端代码检查下一步,如果是,然后再次点击按钮。
验证码:

protected void Page_Load(object sender, EventArgs e)
    {
    }
    
    protected void cmdProcess_Click(object sender, EventArgs e)
    {
        int Step = Convert.ToInt32(pStep.Value);
        int Steps = Convert.ToInt32(pSteps.Value);

        switch (Step)
        {
            case 1:
                // code here for step one
                Thread.Sleep(2000);
                // if more steps, then setup next message
                pStep.Value = "2";
                lblmsg.Text = "Sending emails...";
                return;

            case 2:
                // code here for step 2
                Thread.Sleep(3000);
                pStep.Value = "3";
                lblmsg.Text = "Building Projects for customers...";
                return;

            case 3:
                // code here for step 3 - Building project for custoemrs
                Thread.Sleep(2000);
                pStep.Value = "4";
                lblmsg.Text = "Taking pet dog for a walk..";
                return;

            case int n when (n > 3) && (n < Steps):
                Thread.Sleep(1000);
                pStep.Value = (Step + 1).ToString();
                lblmsg.Text = "Working, please wait";
                return;

            case int n when (n == Steps):

                // process code here for last step
                Thread.Sleep(1000);

                // we done last step, so stop
                // last step - clear out lbl msg to STOP processing
                lblmsg.Text = ""; // blank message - stop processor
                return;
        }
    }


结果是这样的:


的数据
因此,上述方法适用于大约20或75个过程步骤。如果您需要更多步骤,则需要采用不同的技术,例如SignalR。

相关问题