我有这么长的过程可能需要1个小时。
这个过程包括每年运行的许多步骤。我的主要问题是:
如何在此过程中为最终用户提供信息丰富的实时进度,而不仅仅是虚拟装载栏。
int index = Convert.ToInt32(e.CommandArgument);
bool done = false;
int res = -1;
int fromVal = int.Parse(gv_balance.Rows[index].Cells[0].Text);
int toVal = int.Parse(gv_balance.Rows[index].Cells[1].Text);
int finMonth = 1;
int finYear = 0;
int EndServ = 0;
int calcYear = int.Parse(gv_balance.Rows[index].Cells[2].Text);
int total;
total = ((toVal - fromVal) + 1);
string msg = string.Empty;
int confirm = Balance.GetConfirmState(calcYear);
if (confirm == 0)
{
RadProgressContext progress = RadProgressContext.Current;
progress.Speed = "N/A";
finYear = fromVal;
for (int i = fromVal; i <= toVal; i++)
{
decimal ratio;
//Load New Employees
if (toVal - fromVal > 0)
{
ratio = ((decimal)toVal - i) / (toVal - fromVal) * 100;
}
else
{
ratio = ((decimal)toVal - i) / 1 * 100;
}
progress.PrimaryTotal = total;
progress.PrimaryValue = total;
progress.PrimaryPercent = 100;
progress.SecondaryTotal = 100; // total;
progress.SecondaryValue = ratio;//i ;
progress.SecondaryPercent = ratio; //i;
progress.CurrentOperationText = "Step " + i.ToString();
if (!Response.IsClientConnected)
{
//Cancel button was clicked or the browser was closed, so stop processing
break;
}
progress.TimeEstimated = (toVal - i) * 100;
//Stall the current thread for 0.1 seconds
System.Threading.Thread.Sleep(100);
EndServ = i + 1;
if (i == fromVal)
{
//--->STEP1
//Load intial data
int intial = Balance.PrepareIntialData(calcYear);
//--->STEP2
res = Balance.CalcEndServed(calcYear, EndServ - 1, 6, 30);
}
//--->STEP3
int newEmps = Balance.PrepareNewEmployees(calcYear, i);
for (int j = 0; j < 2; j++)
{
if (j == 0)
{
finMonth = 7;
finYear = i;
}
else
{
finMonth = 1;
finYear = i + 1;
}
//--->STEP4
int promotion1 = Balance.PreparePromotionFirst(finYear, finMonth, calcYear);
//--->STEP5
int promotion2 = Balance.PreparePromotionSecond(finYear, finMonth, calcYear);
//--->STEP6
int appointment1 = Balance.PrepareAppointmentFirst(finYear, finMonth, calcYear);
//--->STEP7
int appointment2 = Balance.PrepareAppointmentSecond(finYear, finMonth, calcYear);
//--->STEP8
int bonus = Balance.PrepareBonus(finMonth, finYear, 0, calcYear);
//--->STEP9
int salary = Balance.PrepareSalary(finYear, finMonth, calcYear);
(((CheckBox)gv_balance.Rows[index].Cells[3].FindControl("chk_redirect")).Checked == true)
{
//--->STEP9
int acco = Balance.PrepareFinanceAccount(finYear, finMonth, calcYear);
}
}
//--->STEP10
res = Balance.CalcEndServed(calcYear, EndServ, 6, 30);
Balance.CalcStudy(calcYear);
UpdateProgressContext();
if (res < 0)
{
success_lb.Visible = false;
error_lb.Visible = true;
error_lb.Text = "ERROR";
}
else
{
done = true;
success_lb.Visible = true;
error_lb.Visible = false;
success_lb.Text = "Success";
}
}
}
我想以示例的方式显示当前步骤:
(Promotion 1 ) in ---> 1-2018
以及整个过程在估计时间旁边的百分比。
答案 0 :(得分:13)
要使用signalR报告很长任务的进度,您可以执行以下操作(它只是一个示例,说明它如何工作):
服务器部分
我们首先映射SignalR。
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
}
我们创建了一个集线器类(不要忘记安装signalr包):
(如果您要向所有关联用户或特定用户组报告进度,请查看此处:http://www.asp.net/signalr/overview/guide-to-the-api/working-with-groups)
在给定的示例中,它仅向Start
函数的调用者报告进度。
public class MyHub : Hub
{
public void Start(string arg)
{
Task.Run(() =>
{
AVeryLongTask();
});
}
//simulate a long task
void AVeryLongTask()
{
for (int i = 0; i < 10000; i++)
{
Thread.Sleep(100);
Clients.Caller.ReportProgress("AVeryLongTask", i * 100 / 10000);
}
}
}
客户端部分
在html中你必须添加这些引用:
<!--Script references. -->
<!--Reference the jQuery library. -->
<script src="Scripts/jquery-1.6.4.min.js"></script>
<!--Reference the SignalR library. -->
<script src="/Scripts/jquery.signalR-2.0.0.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="/signalr/hubs"></script>
现在Js部分从集线器获得进展:
$(function() {
// Declare a proxy to reference the hub.
var hub = $.connection.myHub;
// Create a function that the hub can call to report progress.
hub.client.reportProgress = function(functionName, progress) {
$('#progression').append('<li><strong>' + progress + '</strong>: ' + functionName + '</li>');
};
// Start the connection.
$.connection.hub.start().done(function() {
$('#startlongprocess').click(function() {
//start the long process
hub.server.start("arg");
alert("started");
});
});
});
进度的html容器和开始按钮:
<div class="container">
<input type="button" id="startlongprocess" value="Send" />
<ul id="progression"></ul>
</div>
如果您需要更多解释,请不要犹豫。
(我的例子是基于来自信号员团队的这个http://www.asp.net/signalr/overview/getting-started/tutorial-getting-started-with-signalr)
答案 1 :(得分:5)
您可以使用Web套接字将进度更新推送到客户端。 SignalR是一个dotnet库,它包裹了websockets并在没有websockets的地方回落。网上有综合示例,展示了如何使用SignalR实现进度报告,因此无需重复。看看这里:
https://github.com/dragouf/SignalR.Progress
或在这里:
https://www.safaribooksonline.com/blog/2014/02/06/server-side-signalr/
例如。
答案 2 :(得分:2)
以下是我认为可以解决问题的简化问题。如果在任务中运行长操作,则可以使用状态对象更新应用程序。如果您的应用程序是WPF,并且您绑定了状态,它将自动更新。在WinForms中,您可以绑定或仅实现事件处理程序。
void Main()
{
var status = new Status();
object locker = new object();
status.PropertyChanged += Status_PropertyChanged;
//
// Long running job in a task
//
var task = new Task((s) =>
{
for(int i = 0; i < 1000; i++)
{
Task.Delay(TimeSpan.FromSeconds(5)).Wait();
//Thread.Sleep(5000);
lock (locker)
{
status.Message = string.Format("Iteration: {0}", i);
}
}
}, status);
//
// start and wait for the task to complete. In a real application, you may end differently
task.Start();
task.Wait();
}
static void Status_PropertyChanged(object sender,
PropertyChangedEventArgs e)
{
var s = sender as Status;
if(s != null && string.Equals(e.PropertyName, "Message"))
{
Console.WriteLine( s.Message);
}
}
public class Status : PropertyNotifier
{
private string _Message = string.Empty;
public string Message
{
get { return _Message; }
set { SetField(ref _Message, value); }
}
}
public abstract class PropertyNotifier : INotifyPropertyChanged, INotifyPropertyChanging
{
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged; // ? = new Delegate{};
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanging(string propertyName)
{
PropertyChangingEventHandler handler = PropertyChanging;
if (handler != null) handler(this, new PropertyChangingEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
OnPropertyChanging(propertyName);
field = value;
OnPropertyChanged(propertyName);
return true;
}
}