我正在尝试创建一个文件复制应用程序。我有一个BackgroudWorkers在做这项工作,到目前为止它工作正常。它是如何工作的,我有一个表单,源和目标文件夹字段和一个复制按钮。"复制"按钮使用后台辅助角色触发复制操作。进度条更新等。现在我需要实现队列类型的操作。我需要添加其他源和目标复制操作并将其添加到队列中。我尝试使用以下方法:
Queue<MethodInvoker> MyQueue = new Queue<MethodInvoker>();
MyQueue.Enqueue(new MethodInvoker(() =>CopyStuff(1)));
MyQueue.Enqueue(new MethodInvoker(() =>CopyStuff(2)));
MethodInvoker bb = MyQueue.Dequeue(); //(I Forgot this part)
bb();
bb = MyQueue.Dequeue();
bb();
问题是,因为它是后台工作线程,所以它不会等待第一个操作完成。关于如何做到这一点的任何建议?修复我的代码后,它可以工作,除了它在 UI 线程上运行,锁定控件。
更新 1:
这有效,但在主线程上运行,用户在运行时无法使用控件:
BlockingCollection<MethodInvoker> bCollection = new BlockingCollection<MethodInvoker>(boundedCapacity: 2);
Task producerThread = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 2; ++i)
{
bCollection.Add(CopyStuff);
}
bCollection.CompleteAdding();
});
foreach (MethodInvoker item in bCollection.GetConsumingEnumerable())
{
BeginInvoke(item);
}
更新 2:
在控制台应用中工作,但不能在 Windows 窗体应用程序中工作。
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AsyncCopy
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public class AsyncCopy
{
private static Queue<Action> MyQueue = new Queue<Action>();
public async Task EnqueueAndCopy(Action[] actionList)
{
foreach (var action in actionList)
{
MyQueue.Enqueue(action);
}
while (MyQueue.TryDequeue(out var copyAction)) //Here's the problem on Windows Form Applivcation
{
//If the copyaction is itself async, await directly on the method here instead of running the action in a Task
await Task.Factory.StartNew(copyAction);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
var asyncCopy = new AsyncCopy();
//In a typical usage, this will call be awaited
//In your case, make this call from a async method and call it from the UI thread
asyncCopy.EnqueueAndCopy(
new Action[] {
() => CopyStuff (1),
() => CopyStuff (2)
}
);
//Loop to confirm the processing is asynchronous
for (int i = 0; i <= 20; i++)
{
Console.WriteLine($"{i}");
Thread.Sleep(300);
}
}
//Copy process simulation
static void CopyStuff(int i)
{
Console.WriteLine($"Copying {i}");
Thread.Sleep(3000);
Console.WriteLine($"Copied {i}");
}
}
}
如果您需要在其他副本正在处理时异步排队复制过程,我建议您使用生产者使用者模式。请参阅 https://www.dotnetcurry.com/patterns-practices/1407/producer-consumer-pattern-dotnet-csharp
但是一个简单的异步等待也可以在您的情况下工作
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
namespace stackoverflow {
class Program {
static void Main (string[] args) {
var asyncCopy = new AsyncCopy ();
//In a typical usage, this will call be awaited
//In your case, make this call from a async method and call it from the UI thread
asyncCopy.EnqueueAndCopy (
new Action[] {
() => CopyStuff (1),
() => CopyStuff (2)
}
);
//Loop to confirm the processing is asynchronous
for(int i=0; i <= 20; i++)
{
Console.WriteLine($"{i}");
Thread.Sleep(300);
}
}
//Copy process simulation
static void CopyStuff (int i) {
Console.WriteLine ($"Copying {i}");
Thread.Sleep(3000);
Console.WriteLine ($"Copied {i}");
}
}
public class AsyncCopy {
private static Queue<Action> MyQueue = new Queue<Action> ();
public async Task EnqueueAndCopy (Action[] actionList) {
foreach (var action in actionList) {
MyQueue.Enqueue (action);
}
while (MyQueue.TryDequeue (out var copyAction)) {
//If the copyaction is itself async, await directly on the method here instead of running the action in a Task
await Task.Factory.StartNew (copyAction);
}
}
}
}
更新
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async Task CopyAsync(IEnumerable<Action> actionList)
{
foreach (var action in actionList)
{
await Task.Factory.StartNew(action);
}
}
private async void button2_Click(object sender, EventArgs e)
{
await CopyAsync(
new Action[]
{
() => CopyStuff(1),
() => CopyStuff(2)
});
}
//Copy process simulation
static void CopyStuff(int i)
{
Thread.Sleep(3000);
MessageBox.Show(string.Format("File Copied {0}", i));
}
}
}