using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Windows.Forms; namespace Common { public partial class FormProgress : Form { public List Tasks; public DateTime StartTime; public Progress CurrentTask; public FormProgress() { InitializeComponent(); Tasks = new List(); CurrentTask = null; } private void timer1_Tick(object sender, EventArgs e) { 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 = ""; } private void FormProgress_Load(object sender, EventArgs e) { Theme.UseTheme(this); DpiScaling.Apply(this); Icon = Icon.ExtractAssociatedIcon(Application.Execut‌​ablePath); timer1_Tick(this, null); timer1.Enabled = true; progressBar1.Visible = false; } private void FormProgress_FormClosing(object sender, FormClosingEventArgs e) { 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 bg = new BackgroundWorker(); bg.DoWork += bg_DoWork; bg.RunWorkerCompleted += bg_DoWorkerCompleted; bg.RunWorkerAsync(); } else Close(); } else 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 bg = new BackgroundWorker(); bg.DoWork += bg_DoWork; bg.RunWorkerCompleted += bg_DoWorkerCompleted; bg.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); } } }