テストWPFプロジェクトTPLデータフローを使用して特定の親ディレクトリのすべてのサブディレクトリを列挙し、特定のファイル拡張子を持つファイルのリストを作成しようとしています。 ".xlsx"最初のdirToFilesBlockと最後のfileActionBlockの2つのブロックを使用します。再帰を伴うTPLデータフロー
すべてのサブディレクトリを通過する再帰的効果を作成するには、最初のブロックに、リンク述語テストを使用して、出力項目がディレクトリであるかどうかを確認するリンクがあります。これは私が非同期プログラミングに関する本で見つけたアプローチです。 2番目のリンクはfileActionBlockへのリンクで、ファイルを正しい拡張子で調べるリンク述部テストに基づいて、ファイルをリストに追加します。
私が抱えている問題は、btnStart_Clickで物事を蹴った後に終了しないことです。つまり、「完了」メッセージを表示するために、イベントハンドラの待機時間を下回ることはありません。私はおそらくdirToFilesBlock.Complete()を呼び出す必要があることを理解していますが、コード内でどこがどのような条件であるべきかわかりません。私はそれがサブディレクトリを与えることからリンクを戻すのを止めるので、最初の投稿の後でそれを呼び出すことはできません。私はInputCountとOutputCountのプロパティを使って作業を試みましたが、それほど遠くには達しませんでした。できるだけデータフローの構造をそのままにしておきたいと思っています。つまり、リンクを介して探索される新しいディレクトリごとにUIを更新し、ユーザーに進捗状況をフィードバックすることができます。
私はTPLデータフローに非常に慣れていて、どんな助けもありがとうございます。ここで
は、分離コードファイルからのコードです:
public partial class MainWindow : Window
{
TransformManyBlock<string, string> dirToFilesBlock;
ActionBlock<string> fileActionBlock;
ObservableCollection<string> files;
CancellationTokenSource cts;
CancellationToken ct;
public MainWindow()
{
InitializeComponent();
files = new ObservableCollection<string>();
lst.DataContext = files;
cts = new CancellationTokenSource();
ct = cts.Token;
}
private Task Start(string path)
{
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
dirToFilesBlock = new TransformManyBlock<string, string>((Func<string, IEnumerable<string>>)(GetFileSystemItems), new ExecutionDataflowBlockOptions() { CancellationToken = ct });
fileActionBlock = new ActionBlock<string>((Action<string>)ProcessFile, new ExecutionDataflowBlockOptions() {CancellationToken = ct, TaskScheduler = uiScheduler});
// Order of LinkTo's important here!
dirToFilesBlock.LinkTo(dirToFilesBlock, new DataflowLinkOptions() { PropagateCompletion = true }, IsDirectory);
dirToFilesBlock.LinkTo(fileActionBlock, new DataflowLinkOptions() { PropagateCompletion = true }, IsRequiredDocType);
// Kick off the recursion.
dirToFilesBlock.Post(path);
return Task.WhenAll(dirToFilesBlock.Completion, fileActionBlock.Completion);
}
private bool IsDirectory(string path)
{
return Directory.Exists(path);
}
private bool IsRequiredDocType(string fileName)
{
return System.IO.Path.GetExtension(fileName) == ".xlsx";
}
private IEnumerable<string> GetFilesInDirectory(string path)
{
// Check for cancellation with each new dir.
ct.ThrowIfCancellationRequested();
// Check in case of Dir access problems
try
{
return Directory.EnumerateFileSystemEntries(path);
}
catch (Exception)
{
return Enumerable.Empty<string>();
}
}
private IEnumerable<string> GetFileSystemItems(string dir)
{
return GetFilesInDirectory(dir);
}
private void ProcessFile(string fileName)
{
ct.ThrowIfCancellationRequested();
files.Add(fileName);
}
private async void btnStart_Click(object sender, RoutedEventArgs e)
{
try
{
await Start(@"C:\");
// Never gets here!!!
MessageBox.Show("Completed");
}
catch (OperationCanceledException)
{
MessageBox.Show("Cancelled");
}
catch (Exception)
{
MessageBox.Show("Unknown err");
}
finally
{
}
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
cts.Cancel();
}
}
}