Basic Goal is that i have four progress bar and want to run them at once as button is pressed and i donot have to use background worker have to do by this.
var t = new Thread(() =>
{
try
{
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
I tried and codded
for (i = 0; i < 4; i++)
{
var t = new Thread(() =>
{
for (double x = 0; x < 10000; x = x + 0.5)
{
progressVal=(int)x;
this.Invoke(new EventHandler(ProgressBar));
Thread.Sleep(2);
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private void ProgressBar(object sender, EventArgs e)
{
progressBar1.Value=progressVal;
}
but cannot think of idea how to manuplate other progress bars
I would put the progress bars into an array:
var pBars = new[] { progressBar1, progressBar2, progressBar3, progressBar4 };
foreach (var pBar in pBars)
{
new Thread(currentPBar =>
{
for (double x = 0; x < 10000; x = x + 0.5)
{
var progress = (int)x;
Action<ProgressBar, int> del = UpdateProgress;
Invoke(
del,
new object[] { (ProgressBar)currentPBar, progress }
);
Thread.Sleep(2);
}
}).Start(pBar);
}
and the UpdateProgress method:
private void UpdateProgress(ProgressBar pBar, int progress)
{
pBar.Value = progress;
}
This being said, using a BackgroundWorker is far more adapted to your scenario.
Related
I'm trying to write a C# application that updates a progress bar as multiple files have been copied through. I am using this method to do the copying which takes a Dictionary<string, string>:
public static async Task CopyFiles(Dictionary<string, string> files, IProgress<int> progressCallback)
{
for (var x = 0; x < files.Count; x++)
{
var item = files.ElementAt(x);
var from = item.Key;
var to = item.Value;
using (var outStream = new FileStream(to, FileMode.Create, FileAccess.Write, FileShare.Read))
{
using (var inStream = new FileStream(from, FileMode.Open, FileAccess.Read, FileShare.Read))
{
await inStream.CopyToAsync(outStream);
}
}
var percentComplete = ((x + 1) / files.Count) * 100;
//progressCallback((int)((x + 1) / files.Count) * 100);
progressCallback.Report(percentComplete);
}
}
Inside my main class I am using the following code to try to update my progress bar (progressBar1) but this code doesn't appear to be working, it seems to complete the ProgressBar towards the END of the copying of both files and it takes like a second to complete, not sure why this is happening.
private async void button4_Click(object sender, EventArgs e)
{
button4.Enabled = false;
var progress = new Progress<int>(percent =>
{
progressBar1.Value = percent;
});
await Copier.CopyFiles(new Dictionary<string, string> {
{ Source1, Destination1 },
{ Source2, Destination2 }
},
progress);
button4.Enabled = true;
MessageBox.Show("Completed");
}
}
The problem is caused because the integer division x + 1 / files.Count returns zero for every x except the last. You can fix this by multiplying by 100 first (100*(x+1)/files.Count) but there are better alternatives.
There's no need to calculate and report a percentage in CopyFiles. You can set the progress bar's Maximum value :
private async void button4_Click(object sender, EventArgs e)
{
button4.Enabled = false;
var files = new Dictionary<string, string> {
{ Source1, Destination1 },
{ Source2, Destination2 }
};
progressBar1.Maximum=files.Count;
progressBar1.Value =0;
var progress = new Progress<int>(x =>
{
progressBar1.Value = x+1;
});
await Copier.CopyFiles(files,progress);
button4.Enabled = true;
MessageBox.Show("Completed");
}
}
And report just the current iteration :
public static async Task CopyFiles(Dictionary<string, string> files, IProgress<int> progressCallback)
{
for (var x = 0; x < files.Count; x++)
{
...
progressCallback.Report(x);
}
}
IProgress< T> can handle complex objects, not just primitive types. It's possible to report both the iteration and the file names for display in the status bar :
record CopyProgress(int Iteration, string From, string To);
...
var progress = new Progress<int>(x =>
{
progressBar1.Value = x.Iteration;
statusText.Text = $"Copied {x.From} to {x.To}";
});
...
progressCallback.Report(new CopyProgress(x,from,to);
I have the following code:
void Selection()
{
bool solutionFound = false;
int generation = 0;
int distance = int.MaxValue;
while(!solutionFound)
{
generation++;
for (int i = 0; i < population.Length; i++)
{
population[i].CalcFitness(target);
}
matingPool = new List<DNA>();
for (int i = 0; i < population.Length; i++)
{
int n = (int)(population[i].fitness * 100);
for (int j = 0; j < n; j++)
{
matingPool.Add(population[i]);
}
}
for (int i = 0; i < population.Length; i++)
{
int a = StaticRandom.Instance.Next(matingPool.Count);
int b = StaticRandom.Instance.Next(matingPool.Count);
DNA partnerA = matingPool[a];
DNA partnerB = matingPool[b];
if(partnerA.GetPhrase().Equals(partnerB.GetPhrase()))
{
while(partnerA.GetPhrase().Equals(partnerB.GetPhrase()))
{
a = StaticRandom.Instance.Next(matingPool.Count);
b = StaticRandom.Instance.Next(matingPool.Count);
partnerA = matingPool[a];
partnerB = matingPool[b];
}
}
DNA child = partnerA.Crossover(partnerB);
child.Mutate(mutationRate);
population[i] = child;
ThreadHelperClass.SetText(this, display_lbl, i + ": " + child.GetPhrase());
ThreadHelperClass.SetText(this, gen_lbl, "Generations: " + generation);
int compute = LevenshteinDistance.Compute(target, child.GetPhrase());
if(compute < distance)
{
distance = compute;
ThreadHelperClass.SetText(this, bestPhrase_lbl, "Best Phrase: " + child.GetPhrase());
}
if(child.GetPhrase().Equals(target))
{
solutionFound = true;
break;
}
}
}
}
and the following code
public static class ThreadHelperClass
{
delegate void SetTextCallback(Form f, Control ctrl, string t);
public static void SetText(Form form, Control control, string text)
{
//Invoke requires compares the thread ID of the calling thread
//to the thread ID of the creating thread
//If they are different InvokeRequired sets to true
if (control.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
form.Invoke(d, new Object[] { form, control, text });
}
else
control.Text = text;
}
}
I send Selection to another thread using:
Task.Factory.StartNew(() => Selection(), cToken.Token);
I've already tried to set the ThreadHelper class to use BeginInvoke instead of Invoke and it locks up my UI on the first iteration of the Selection method.
I've also tried to end the task using cToken.Cancel(). This still locks up my UI when the user clicks the stop_btn.
Is there a way I can stop this from happening?
When I need to invoke some code in the specified thread, i am using something like this:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
delegate void MethodToInvokeDelegate(string foo, int bar);
void MethodToInvoke(string foo, int bar)
{
DoSomeWork(foo);
DoMoreWork(bar);
}
void SomeMethod()
{
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(new MethodToInvokeDelegate(MethodToInvoke), new object[] {S, I});
}
This code works fine, but it's quite heavy. I'd like to make it without declaring MethodToInvoke and MethodToInvokeDelegate - using an anonymous method. But I can't figure out how to pass parameters to it.
I can't write this like:
dispatcher.BeginInvoke((Action)delegate() { DoSomeWork(S); DoMoreWork(I); });
I need to actually pass parameters to method.
Is it any way to write it short and simple?
Example:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
void SomeMethod()
{
for (int i = 0; i < 3; i++)
dispatcher.BeginInvoke( { ArrayToFill[i] = 10; } );
}
This code will not work: method will be called with i = 1, 2, 3 and will raise IndexOutOfRange exception. i will be incremented before method begins to execute. So we need to rewrite it like:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
delegate void MethodToInvokeDelegate(int i);
void MethodToInvoke(int i)
{
ArrayToFill[i] = 10;
}
void SomeMethod()
{
for (int i = 0; i < 3; i++)
dispatcher.BeginInvoke(new MethodToInvokeDelegate(MethodToInvoke), new object[] {i});
}
if you wish to avoid creating a delegate type for each call, make use of Action<>, Action<,>, etc
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(
(Action<string, int>)((foo, bar) =>
{
MessageBox.Show(bar.ToString(), foo);
//DoSomeWork(foo);
//DoMoreWork(bar);
}),
new object[] { S, I }
);
an example with ArrayToFill[j] = 10; action can be fixed very simple:
for (int i = 0; i < 3; i++)
{
int j = i;
// lambda captures int variable
// use a new variable j for each lambda to avoid exceptions
dispatcher.BeginInvoke(new Action(() =>
{
ArrayToFill[j] = 10;
}));
}
Try this:
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(new Action(() =>
{
DoSomeWork(S);
DoMoreWork(I);
}));
[EDIT]
In response to your modified question:
The issue you are seeing there is modified closure problem.
To fix it, you merely need to copy the argument before invoking the method:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
for (int i = 0; i < 3; i++)
{
int index = i;
dispatcher.BeginInvoke(new Action(() => { ArrayToFill[index] = 10; } ));
}
yourUIcontrol.BeginInvoke(new MethodInvoker(delegate {
//your code goes here
}));
I am using background worker for process meantime i need to update progressbar.
I update the progressBar value using backgroundworker.ReportProgress but the values are updated to the user
after the background thread is completed.But i need to show the progress bar update while backgroundworker is running.
my code is
public bool IsClosed()
{
bool profileClosed = false;
for (int i = 0; i < originalEntityList.Count; i++)
{
if (originalEntityList[i] is Core.DatabaseServices.Point)
entityList.RemoveAt(i);
}
CoreApp.ModelSpace.customProgressValue = 0;
CoreApp.ModelSpace.TotalPercentage = OriginalEntityList.Count;
if (!CoreApp.ModelSpace.backgrdWorker.IsBusy)
CoreApp.ModelSpace.backgrdWorker.RunWorkerAsync();
CoreApp.ModelSpace.IndicateProgress(true, new EventArgs());
if (!profileClosed)
UtilitiesLocalization.ShowMessage(UtilitiesLocalization.ProfileNotClosedMessage, UtilitiesLocalization.InvalidProfileTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning);
return profileClosed;
}
private void backgrdWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
if (!checkProfileInvalid)
{
Thread overlapThread = new Thread(new ThreadStart(CheckOverlapEntities));
overlapThread.IsBackground = true;
overlapThread.Start();
overlapThread.Join();
}
}
public static bool CheckOverlapEntities()
{
OverlapedEntities.Clear();
OriginalCollection = new List<Entity>(EntityCollection);
TempCollection = new List<Entity>(EntityCollection);
List<Thread> threadList = new List<Thread>();
for (int id = 0; id < TempCollection.Count; id++)
{
CoreApp.ModelSpace.backgrdWorker.ReportProgress(id+1);
Entity currentEntity = TempCollection[id];
if (currentEntity is PolyLine3d && (currentEntity as PolyLine3d).IsClosed) continue;
Thread tempThread = new Thread(new ParameterizedThreadStart(FindOverlapInParallel));
threadList.Add(tempThread);
tempThread.Start(currentEntity);
if (threadList.Count == MaxThread)
{
for (int i = 0; i < threadList.Count; i++)
{
threadList[i].Join();
if (checkProfileInvalid) break;
}
threadList = new List<Thread>();
}
}
CoreApp.ModelSpace.backgrdWorker.ReportProgress(100);
if (OverlapedEntities.Count > 0)
return true;
return false;
}
void backgrdWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
colorProgressBar1.Value = e.ProgressPercentage;
colorProgressBar1.PerformStep();
if (e.ProgressPercentage == colorProgressBar1.Maximum)
colorProgressBar1.Value = 0;
}
Thanks in Advance..
public class Program
{
static void Main(string[] args)
{
var myThread = new TestThread();
Thread t = new Thread(new ThreadStart(myThread.PrintName));
Thread t1 = new Thread(new ThreadStart(myThread.PrintType));
t.Start();
t1.Start();
Console.Read();
}
}
public class TestThread
{
public void PrintName()
{
for (int i = 1; i <= 50; i++)
{
Console.WriteLine("Name {0}", i);
}
}
public void PrintType()
{
for (int i = 100; i <= 180; i++)
{
Console.WriteLine("Type {0}", i);
}
}
}
Here How can i fixed it show that i can generate output in sequential i.e
first output of Name then only output of Type... Also I want to know about using Lock() in threads? where can i get good example. I am beginners in threading and need v.simple example.
Try this:
var myThread = new TestThread();
var x=Task.Factory.StartNew(() => myThread.PrintName());
x.ContinueWith(p => PrintType());
x.Wait();
You can look at this
There are multiple other articles, just google for 'introduction threading c#'.
The purpose of threads is to allow things to happen at the same time. If you want things to happen one after another (i.e. sequentially), then do not use threads:
var obj = new TestThread();
obj.PrintName();
obj.PrintType();
Console.Read();
Or put PrintName and PrintType into the same thread, in order to keep the UI responsive:
var myThread = new TestThread();
Thread t = new Thread(new ThreadStart(
() => {
myThread.PrintName(); myThread.PrintType();
}
));
t.Start();
// Do things in the UI meanwhile
for (i = 0; i < 100; i++) {
Console.WriteLine("UI thread {0}", i);
}
Console.Read();
//This will run two operation in sequence.
public class TestThread
{
public object obj = new object();
public void PrintName()
{
Monitor.Enter(obj);
for (int i = 1; i <= 50; i++)
{
Console.WriteLine("Name {0}", i);
}
Monitor.Exit(obj);
}
public void PrintType()
{
Monitor.Enter(obj);
for (int i = 100; i <= 180; i++)
{
Console.WriteLine("Type {0}", i);
}
Monitor.Exit(obj);
}
}
That will do the trick, you should read carefully and try to do it with 3 loops by yourself:
private static void SimpleLockTest()
{
Task[] myTasks = new Task[2];
myTasks[0] = Task.Factory.StartNew(() =>
{
LockTestThreadOne();
});
myTasks[1] = Task.Factory.StartNew(() =>
{
LockTestThreadTwo();
});
Task.WaitAll(myTasks);
Console.WriteLine("Done, press ENTER to quit");
Console.ReadLine();
}
private static object locker = new object();
private static void LockTestThreadOne()
{
Monitor.Enter(locker);
for (int i = 1; i <= 50; i++)
{
Console.WriteLine("Name {0}", i);
Monitor.Pulse(locker);
Monitor.Wait(locker);
}
Monitor.Exit(locker);
}
private static void LockTestThreadTwo()
{
Monitor.Enter(locker);
for (int i = 100; i <= 180; i++)
{
Console.WriteLine("Type {0}", i);
Monitor.Pulse(locker);
Monitor.Wait(locker, 10);
}
Monitor.Exit(locker);
}