using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows.Forms; namespace Common { public partial class FormProgress : FormEx { public List Tasks; public DateTime StartTime; public Progress CurrentTask; private bool _canClose; public FormProgress() { InitializeComponent(); Tasks = new List(); CurrentTask = null; _canClose = false; } private void timer1_Tick(object sender, EventArgs e) { const int steps = 10000; int total = Tasks.Count * steps; int current; int index = Tasks.IndexOf(CurrentTask); if (index >= 0) { current = index * steps; if (CurrentTask.Total > 0) current += (int)(index + ((double)CurrentTask.Current / CurrentTask.Total) * steps); } else current = 0; progressBar1.Maximum = total; if (current <= total) progressBar1.Value = current; else progressBar1.Value = total; progressBar1.Visible = current > 0; if (CurrentTask != null) labelOperation.Text = CurrentTask.Operation; else labelOperation.Text = ""; if ((current > 0) && (total > 0)) { TimeSpan timeDiff = TimeSpan.FromSeconds((DateTime.Now - StartTime).TotalSeconds / current * (total - current)); string remaining = timeDiff.ToString(@"hh\:mm\:ss"); if (timeDiff.TotalDays >= 1) remaining = Math.Truncate(timeDiff.TotalDays) + " days " + remaining; labelTime.Text = @"Remaining time: " + remaining; } else labelTime.Text = ""; // Update task bar progress if (progressBar1.Value < progressBar1.Maximum) { TaskBarProgress.SetValue(Handle, progressBar1.Value, progressBar1.Maximum); if (progressBar1.Value == 0) { TaskBarProgress.SetState(Handle, TaskBarProgress.TaskBarStates.Indeterminate); } } else { TaskBarProgress.SetState(Handle, TaskBarProgress.TaskBarStates.NoProgress); } } private void FormProgress_Load(object sender, EventArgs e) { timer1_Tick(this, null); timer1.Enabled = true; progressBar1.Visible = false; } private void FormProgress_FormClosing(object sender, FormClosingEventArgs e) { e.Cancel = !_canClose; CurrentTask.Terminated = true; timer1.Enabled = false; } private void bg_DoWork(object sender, DoWorkEventArgs e) { CurrentTask.Execute(); CurrentTask.Completed = !CurrentTask.Terminated; } private void bg_DoWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) { CurrentTask.Terminated = true; MessageBox.Show(e.Error.Message, @"Error in background task", MessageBoxButtons.OK, MessageBoxIcon.Error); } if (!CurrentTask.Terminated) { int nextIndex = Tasks.IndexOf(CurrentTask) + 1; if (nextIndex < Tasks.Count) { CurrentTask = Tasks[nextIndex]; BackgroundWorker backgroundWorker = new BackgroundWorker(); backgroundWorker.DoWork += bg_DoWork; backgroundWorker.RunWorkerCompleted += bg_DoWorkerCompleted; backgroundWorker.RunWorkerAsync(); } else { _canClose = true; Close(); } } else { _canClose = true; Close(); } } public void AddTask(string name, Progress.CallbackEventHandler progressCallback) { Progress newTask = new Progress { Terminated = false, Total = 0, Current = 0, Operation = name }; newTask.Callback += progressCallback; Tasks.Add(newTask); } public void StartTask(string name, Progress.CallbackEventHandler progressCallback) { Tasks.Clear(); AddTask(name, progressCallback); Start(); } public void Start() { if (Tasks.Count > 0) { StartTime = DateTime.Now; CurrentTask = Tasks.First(); BackgroundWorker backgroundWorker = new BackgroundWorker(); backgroundWorker.DoWork += bg_DoWork; backgroundWorker.RunWorkerCompleted += bg_DoWorkerCompleted; backgroundWorker.RunWorkerAsync(); ShowDialog(); } } public bool Completed() { int completed = 0; foreach (var task in Tasks) { if (task.Completed) completed += 1; } return completed == Tasks.Count; } } public interface IProgress { void SetTotal(int value); void SetProgress(int value); bool GetTerminated(); void SetOperation(string text); void Execute(); } public class Progress : IProgress { public int Total; public int Current; public bool Terminated; public bool Completed; // If task was not terminated during execution. public string Operation; public delegate void CallbackEventHandler(Progress progress); public event CallbackEventHandler Callback; public void SetTotal(int value) { Total = value; } public void SetProgress(int value) { Current = value; } public bool GetTerminated() { return Terminated; } public void SetOperation(string text) { Operation = text; } public void Execute() { Callback?.Invoke(this); } } }