182 lines
5.6 KiB
C#
182 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
|
|
namespace MaterialSkin.Controls
|
|
{
|
|
public partial class MaterialCancellableLoader : MaterialForm
|
|
{
|
|
private readonly Dictionary<string, (MaterialProgressBar ProgressBar, Label Label, MaterialFlatButton CancelButton, CancellationTokenSource CancellationTokenSource)> _loadingProcesses;
|
|
public event EventHandler<string> LoadingCancelled;
|
|
|
|
public MaterialCancellableLoader()
|
|
{
|
|
InitializeComponent();
|
|
RemoveMessageFilter();
|
|
_loadingProcesses = new Dictionary<string, (MaterialProgressBar, Label, MaterialFlatButton, CancellationTokenSource)>();
|
|
this.MaximizeBox = false;
|
|
this.MinimizeBox = false;
|
|
this.StartPosition = FormStartPosition.CenterScreen;
|
|
this.Width = 450;
|
|
|
|
}
|
|
|
|
public CancellationToken StartLoading(string title)
|
|
{
|
|
if (_loadingProcesses.ContainsKey(title))
|
|
{
|
|
return _loadingProcesses[title].CancellationTokenSource.Token;
|
|
}
|
|
|
|
var cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
var progressBar = new MaterialProgressBar
|
|
{
|
|
Width = this.ClientSize.Width - 120, // Leave space for cancel button
|
|
Height = 20,
|
|
Top = 50 + (_loadingProcesses.Count * 60),
|
|
Left = 10,
|
|
Style = ProgressBarStyle.Marquee,
|
|
MarqueeAnimationSpeed = 30,
|
|
Value = 50,
|
|
BackColor = Color.White
|
|
};
|
|
|
|
var label = new Label
|
|
{
|
|
Text = title,
|
|
AutoSize = true,
|
|
Top = progressBar.Top - 20,
|
|
Left = progressBar.Left,
|
|
BackColor = Color.White,
|
|
ForeColor = SkinManager.GetPrimaryTextColor()
|
|
};
|
|
|
|
var cancelButton = new MaterialFlatButton
|
|
{
|
|
Text = "Cancel",
|
|
Width = 80,
|
|
Height = 30,
|
|
Top = progressBar.Top - 5,
|
|
Left = progressBar.Right + 10,
|
|
UseVisualStyleBackColor = true
|
|
};
|
|
|
|
// Capture the title in the closure properly
|
|
var capturedTitle = title;
|
|
cancelButton.Click += (sender, e) =>
|
|
{
|
|
CancelLoading(capturedTitle);
|
|
};
|
|
|
|
_loadingProcesses[title] = (progressBar, label, cancelButton, cancellationTokenSource);
|
|
|
|
this.Controls.Add(label);
|
|
this.Controls.Add(progressBar);
|
|
this.Controls.Add(cancelButton);
|
|
|
|
|
|
|
|
if (!this.Visible)
|
|
{
|
|
this.Show();
|
|
}
|
|
|
|
this.Refresh();
|
|
return cancellationTokenSource.Token;
|
|
}
|
|
|
|
public void FinishLoading(string title)
|
|
{
|
|
if (_loadingProcesses.TryGetValue(title, out var components))
|
|
{
|
|
this.Controls.Remove(components.ProgressBar);
|
|
this.Controls.Remove(components.Label);
|
|
this.Controls.Remove(components.CancelButton);
|
|
components.CancellationTokenSource.Dispose();
|
|
_loadingProcesses.Remove(title);
|
|
RearrangeControls();
|
|
}
|
|
|
|
if (_loadingProcesses.Count == 0)
|
|
{
|
|
this.Hide();
|
|
}
|
|
}
|
|
|
|
public void CancelLoading(string title)
|
|
{
|
|
if (_loadingProcesses.TryGetValue(title, out var components))
|
|
{
|
|
components.CancellationTokenSource.Cancel();
|
|
LoadingCancelled?.Invoke(this, title);
|
|
FinishLoading(title);
|
|
}
|
|
}
|
|
|
|
public void CancelAllLoading()
|
|
{
|
|
var titles = _loadingProcesses.Keys.ToList();
|
|
foreach (var title in titles)
|
|
{
|
|
CancelLoading(title);
|
|
}
|
|
}
|
|
|
|
public bool IsLoading(string title)
|
|
{
|
|
return _loadingProcesses.ContainsKey(title);
|
|
}
|
|
|
|
public bool HasActiveLoading => _loadingProcesses.Count > 0;
|
|
|
|
public IEnumerable<string> ActiveLoadingTitles => _loadingProcesses.Keys.ToList();
|
|
|
|
private void RearrangeControls()
|
|
{
|
|
int index = 0;
|
|
foreach (var components in _loadingProcesses.Values)
|
|
{
|
|
var newTop = 50 + (index * 60);
|
|
components.ProgressBar.Top = newTop;
|
|
components.Label.Top = newTop - 20;
|
|
components.CancelButton.Top = newTop - 5;
|
|
index++;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void OnFormClosing(FormClosingEventArgs e)
|
|
{
|
|
// Don't allow closing if there are active loading processes
|
|
if (_loadingProcesses.Count > 0)
|
|
{
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
|
|
base.OnFormClosing(e);
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
// Cancel all ongoing operations and dispose resources
|
|
foreach (var components in _loadingProcesses.Values)
|
|
{
|
|
components.CancellationTokenSource?.Dispose();
|
|
}
|
|
_loadingProcesses.Clear();
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
}
|
|
} |