Hi @YUI-012 , Welcome to Microsoft Q&A,
In the current code, RunWorkerAsync() may be called every time the arrangement is generated, which will cause an exception because BackgroundWorker cannot run multiple tasks in parallel. Therefore, you should make sure to start the BackgroundWorker when starting the arrangement calculation, rather than checking it every time the arrangement is generated. In order to update the UI in real time during the arrangement generation process, you can update the ListBox or other controls through the ProgressChanged event. Be careful to avoid directly operating the UI in the DoWork event, because cross-thread operations will cause exceptions.
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
namespace _xxx
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> items, int limit, BackgroundWorker worker)
{
if (limit <= 0 || items == null)
yield break;
var itemsList = items.ToList();
var indices = Enumerable.Range(0, itemsList.Count);
foreach (var indicesPerm in GetPermutations(indices, limit, worker))
{
yield return indicesPerm.Select(i => itemsList[i]);
}
}
static IEnumerable<IEnumerable<int>> GetPermutations(IEnumerable<int> indices, int limit, BackgroundWorker worker)
{
int totalPermutations = Factorial(indices.Count()) / Factorial(indices.Count() - limit);
int currentPermutation = 0;
if (limit == 1)
{
foreach (var index in indices)
{
currentPermutation++;
if (worker.CancellationPending)
yield break;
var permutation = new[] { index };
worker.ReportProgress((currentPermutation * 100) / totalPermutations, permutation);
yield return permutation;
}
yield break;
}
var indicesList = indices.ToList();
var subPermutations = GetPermutations(indices, limit - 1, worker);
foreach (var index in indicesList)
{
foreach (var subPerm in subPermutations)
{
if (!subPerm.Contains(index))
{
currentPermutation++;
if (worker.CancellationPending)
yield break;
var permutation = subPerm.Append(index);
worker.ReportProgress((currentPermutation * 100) / totalPermutations, permutation);
yield return permutation;
}
}
}
}
// Helper method to calculate factorial
static int Factorial(int n)
{
return (n == 1 || n == 0) ? 1 : n * Factorial(n - 1);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
string[] items = textBox2.Text.Split(' ');
// Get the limit.
int limit = int.Parse(textBox1.Text);
// Generate permutations
var permutations = GetPermutations(items, limit, worker);
// Collect permutations in a list to return it as the result.
var permutationList = new List<IEnumerable<string>>();
foreach (var perm in permutations)
{
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
permutationList.Add(perm);
}
// Store the result in the DoWorkEventArgs
e.Result = permutationList;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Update the progress bar with the percentage reported
progressBar1.Value = e.ProgressPercentage;
// Output the current permutation to ListBox
var currentPermutation = (IEnumerable<int>)e.UserState;
listBox1.Items.Add(string.Join(" ", currentPermutation));
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Operation was cancelled.");
}
else if (e.Error != null)
{
MessageBox.Show("Error: " + e.Error.Message);
}
else
{
// Clear the ListBox and display all permutations
listBox1.Items.Clear();
// Access the permutations from the result
var permutations = (List<IEnumerable<string>>)e.Result;
foreach (var permutation in permutations)
{
listBox1.Items.Add(string.Join(" ", permutation));
}
MessageBox.Show("Operation completed.");
}
}
private void Btngenerate_Click(object sender, System.EventArgs e)
{
if (!backgroundWorker1.IsBusy)
{
// Clear the previous results.
listBox1.Items.Clear();
// Start the background worker asynchronously.
backgroundWorker1.RunWorkerAsync();
}
else
{
MessageBox.Show("Already generating permutations.");
}
}
}
}
Best Regards,
Jiale
If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.