using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DirectoryTask
{
public partial class MainForm : Form
{
IDirectoryTask task = null;
CancellationTokenSource tokenSource = new CancellationTokenSource();
public MainForm()
{
InitializeComponent();
task = new DirectoryTaskImpl(() => tokenSource, val => tokenSource = val);
task.FileProgress += new EventHandler<ProgressEventArgs>(fileProgress);
task.FolderProgress += new EventHandler<ProgressEventArgs>(folderProgress);
task.ExceptionThrown += new EventHandler<ExceptionEventArgs>(exceptionThrown);
task.Complete += new EventHandler<ExitEventArgs>(complete);
}
private void Entry(string[] path)
{
if (path != null)
{
foreach (var p in path)
{
if (task.Entry(p, tokenSource.Token) == null)
{
errorListBox.Items.Add("停止処理中のため失敗しました");
}
}
}
}
private void Cancel()
{
tokenSource.Cancel();
}
#region 進捗の表示、キャンセルイベント
private void Progress(ProgressBar bar, decimal progress)
{
bar.Visible = true;
bar.Value = decimal.ToInt32(progress);
}
private void complete(object sender, ExitEventArgs e)
{
this.Invoke(new Action(() =>
{
this.fileProgressBar.Visible = false;
this.folderProgressBar.Visible = false;
}));
}
private void exceptionThrown(object sender, ExceptionEventArgs e)
{
this.Invoke(new Action(()
=> this.errorListBox.Items.Add(e.Exception.Message)
));
}
private void folderProgress(object sender, ProgressEventArgs e)
{
this.Invoke(new Action(() =>
{
this.Progress(this.folderProgressBar, e.Progress);
folderDoneLabel.Text = e.Done.ToString();
folderTotalLabel.Text = e.Total.ToString();
}));
}
private void fileProgress(object sender, ProgressEventArgs e)
{
this.Invoke(new Action(() =>
{
this.Progress(this.fileProgressBar, e.Progress);
fileDoneLabel.Text = e.Done.ToString();
fileTotalLabel.Text = e.Total.ToString();
}
));
}
private void cancelButton_Click(object sender, EventArgs e)
{
this.Cancel();
}
private void clearErrorButton_Click(object sender, EventArgs e)
{
this.Invoke(new Action(()
=> this.errorListBox.Items.Clear()
));
}
#endregion
#region ドラッグ・ドロップ
protected override void OnDragEnter(DragEventArgs drgevent)
{
if (drgevent.Data.GetDataPresent(DataFormats.FileDrop))
{
drgevent.Effect = DragDropEffects.Copy;
}
base.OnDragEnter(drgevent);
}
protected override void OnDragDrop(DragEventArgs drgevent)
{
if (drgevent.Data.GetDataPresent(DataFormats.FileDrop))
{
// ドラッグ中のファイルやディレクトリの取得、処理へのエントリ
this.Entry(drgevent.Data.GetData(DataFormats.FileDrop) as string[]);
}
base.OnDragDrop(drgevent);
}
#endregion
}
/// <summary>指定されたファイルパスに対して、<see cref="Task"/> 上で非同期かつ再帰的に処理するインターフェースを定義します。</summary>
public interface IDirectoryTask
{
/// <summary>指定されたパスに対して、<see cref="Task"/> 上で非同期かつ再帰的に処理します。</summary>
/// <param name="path">処理対象のパス。</param>
/// <param name="token"><see cref="CancellationToken"/>。</param>
/// <returns>指定されたパスの処理を実行している <see cref="Task"/>。</returns>
Task Entry(string path, CancellationToken token);
event EventHandler<ExitEventArgs> Complete;
event EventHandler<ExceptionEventArgs> ExceptionThrown;
event EventHandler<ProgressEventArgs> FileProgress;
event EventHandler<ProgressEventArgs> FolderProgress;
}
/// <summary>処理が終了した要因を指定します。</summary>
public enum ExitReason
{
/// <summary>すべての処理対象を処理しました。</summary>
Complete = 0,
/// <summary>処理に失敗しました。</summary>
Fatal = 1,
/// <summary>処理が中断されました。</summary>
Cancel = 2,
}
/// <summary>処理が終了したことを示すイベント引数を定義します。</summary>
public class ExitEventArgs : EventArgs
{
/// <summary>終了状態を取得・設定します。</summary>
public ExitReason Reason { get; set; }
}
/// <summary>処理の進捗が変化したことを示すイベント引数を定義します。</summary>
public class ProgressEventArgs : EventArgs
{
/// <summary>現在の進捗をパーセンテージ(0~100)で取得します。</summary>
public decimal Progress { get { return Total == 0 ? 0M : 100M * Done / Total; } }
/// <summary>終了した件数を取得・設定します。</summary>
public int Done { get; set; }
/// <summary>処理する全体の件数を取得・設定します。</summary>
public int Total { get; set; }
}
/// <summary>処理中に発生した例外のイベント引数を定義します。</summary>
public class ExceptionEventArgs : EventArgs
{
/// <summary>発生した例外を取得・設定します。</summary>
public Exception Exception { get; set; }
}
}