Wait until panel controls are drawn - c#

I have a form, this form has a panel. When the form OnShown fires, I start a background worker to execute a long running code method a set number of times. In this background worker, I add a User Control to the panel one-by-one/per-iteration while displaying a Wait picture on the UI thread.
Problem: My long running code runs faster than the panel can draw the controls I've added to it. Basically, when my form loads, it takes about 1.5 seconds to run the code (I can tell by how fast the wait picture hides itself), however, the child controls on the panel take between 4 and 6 seconds to draw themselves...
As you can imagine this would cause some major confusion to the user in that the Wait image would hide/the code would be done, but the controls wouldn't be shown for another 4 seconds.
So, is there a way to essentially "Wait" until all the child controls on the panel are drawn, so that i can ONLY THEN hide the Wait picture through some mechanism in the Panel control?
If that's not possible, keep in mind that I'm using a User Control and have access to those events as well. So if there's something there I could use to fire AFTER the User Control has drawn itself (or thinks it has), maybe i could use that instead and count until I reach the known count?
Here's my code, obscured a bit to not show any work info/not tell you what I'm doing but should be enough for you to find out if there's something wrong with the code itself...
Legend:
SW() = Show Waiting Picture,
HW() = Hide Waiting Picture,
this.wait = Wait Picture Control with progress bars...
private void MyForm_Shown(object sender, EventArgs e)
{
if (this.SomeList.Count <= 0 || this.SomeObject == null)
this.DialogResult = DialogResult.Abort;
SW();
this.wait.Text = "Loading everything...";
this.wait.TotalBar_Max = this.SomeList.Count;
this.wait.TotalBar_Value = 0;
this.wait.CurrentBar_Max = 100;
BackgroundWorker bkg = new BackgroundWorker();
bkg.DoWork += new DoWorkEventHandler(bkg_DoWork);
bkg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bkg_RunWorkerCompleted);
bkg.RunWorkerAsync();
}
void bkg_DoWork(object sender, DoWorkEventArgs e)
{
foreach (SomeType SomeItem in this.SomeList)
{
//Update Progress bar...
this.Invoke(new MethodInvoker(delegate
{
this.wait.Text = "Loading Specifics for: " + SomeItem.ToString();
this.wait.CurrentBar_Value = 50;
}));
MyControl tmp = new MyControl();
tmp.Name = SomeItem.ToString();
tmp.Text = SomeItem.ToString() + " - " + this.SomeObject.Name;
ServerWorker work = new ServerWorker(SomeItem);
Dictionary<string, List<string>> test = work.LongRunningCode();
//fill in/Init User Control based on long running code results...
if (test["Key1"] != null && test["Key1"].Count > 0)
{
test["Key1"].Sort();
tmp.Key1 = test["Key1"];
}
else
{
tmp.Key1_Available = false;
}
if (test["Key2"] != null && test["Key2"].Count > 0)
{
test["Key2"].Sort();
tmp.Key2 = test["Key2"];
}
else
{
tmp.Key2_Available = false;
}
if (test["Key3"] != null && test["Key3"].Count > 0)
{
test["Key3"].Sort();
tmp.Key3 = test["Key3"];
}
else
{
tmp.Key3_Available = false;
}
//Add user control, and update progress bars...
this.Invoke(new MethodInvoker(delegate
{
if (this.panel1.Controls.Count <= 0)
{
tmp.Top = 5;
tmp.Left = 5;
}
else
{
tmp.Top = this.panel1.Controls[this.panel1.Controls.Count - 1].Bottom + 5;
tmp.Left = 5;
}
this.panel1.Controls.Add(tmp);
this.wait.Text = "Loading Specifics for: " + SomeItem.ToString();
this.wait.CurrentBar_Value = 100;
this.wait.TotalBar_Value += 1;
this.panel1.Refresh();
}));
}
e.Result = true;
}
void bkg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
HW();
}

I found my own solution here:
https://stackoverflow.com/a/6653042/1583649
By building a List within the background worker instead of Invoking the UI thread, and then Panel.Add() on the RunWorkerCompleted event instead, the Wait image was able to stay alive until all the controls were actually drawn on the Panel.

Related

Multithreading - Interrupt Thread upon WinForms Event

I'm working on a C# WinForms project which implements a password manager. One of the features I want to include is a timeout for how long a password is allowed to stay in the system clipboard. I implemented a thread which updates a progress bar & then clears the clipboard before the thread terminates:
private void getPassword(int lifeInSeconds)
{
int maxLifeBarValue = lifeInSeconds * 10;
Thread t = new Thread
(delegate ()
{
//Initialize the progress bar
Invoke((MethodInvoker)delegate
{
lifeBar.Maximum = maxLifeBarValue;
lifeBar.Value = maxLifeBarValue;
lifeBar.Visible = true;
Clipboard.SetText(pd.getAccountPassword(lstAccounts.Text));
});
//Loop to update the progress bar
for (int x = maxLifeBarValue; x >= 0; x--)
{
Thread.Sleep(100);
Invoke((MethodInvoker)delegate
{
lifeBar.Value = x;
});
}
//Clear the system clipboard
Clipboard.SetText(string.Empty);
//Hide the progress bar when we're done
Invoke((MethodInvoker)delegate
{
lifeBar.Visible = false;
});
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
This works, but the problem I'm having is that if the user triggers an event to copy another password (or the same one; it doesn't matter), we now have 2 threads running in the background. This is apparent by the fact that the progress bar is "flipping out" so to speak as each thread is updating it's value independently.
Is there a way in which I can detect & terminate the original thread (if it exists) when the user clicks the copy password button again?
You could keep a reference to the Thread, and then abort the thread before starting a new one. Like this:
private Thread passwordClearThread = null;
private void getPassword(int lifeInSeconds)
{
int maxLifeBarValue = lifeInSeconds * 10;
if (passwordClearThread != null && passwordClearThread.IsAlive)
{
passwordClearThread.Abort();
passwordClearThread.Join();
}
passwordClearThread = new Thread
(() =>
{
//Initialize the progress bar
Invoke((MethodInvoker)delegate
{
lifeBar.Maximum = maxLifeBarValue;
lifeBar.Value = maxLifeBarValue;
lifeBar.Visible = true;
Clipboard.SetText(pd.getAccountPassword(lstAccounts.Text));
});
//Loop to update the progress bar
for (int x = maxLifeBarValue; x >= 0; x--)
{
Thread.Sleep(100);
Invoke((MethodInvoker)delegate
{
lifeBar.Value = x;
});
}
//Clear the system clipboard
Clipboard.Clear();
//Hide the progress bar when we're done
Invoke((MethodInvoker)delegate
{
lifeBar.Visible = false;
});
});
passwordClearThread.SetApartmentState(ApartmentState.STA);
passwordClearThread.Start();
}

Display pop up with animated gif while loading file

The goal of my program is to load a directory into my treeview node, which takes more 10 sec(since the directory resides in a remote PC). During this time I shall add a pop up image of waiting. I copied the answer of this post: How can i show an image while my application is loading
to my code, like:
private void treeView2_AfterSelect(object sender, TreeViewEventArgs e)
{
Form f = new Form();
f.Size = new Size(20, 25);
Image im = Image.FromFile(#"C:\Documents and Settings\JiangC\Documenti\Immagini\loader.gif");
f.FormBorderStyle = FormBorderStyle.None;
f.MinimizeBox = false;
f.MaximizeBox = false;
f.AutoSize = true;
PictureBox pb = new PictureBox();
//pb.Dock = DockStyle.Fill;
pb.SizeMode = PictureBoxSizeMode.AutoSize;
pb.Image = im;
pb.Location = new Point(50, 50);
f.Controls.Add(pb);
f.Show();
// Application.DoEvents();
BuildTree(directory, treeView2.Nodes, treeView2.SelectedNode);
f.Close();
}
What I want to do is that during the loading (when Buildtree() method is implementing) the form f with the picturebox pb will be shown, and after loading they just disappear.
The first problem is in "pb.Dock = DockStyle.Fill;"
If I uncomment it, this form f will not be shown during the loading(but I can see its minimized window in the bottom of the screen). Only if I take off this line the form f could be shown out.
The second problem is "f.Show();" When the form f is shown, the picturebox pb isn't shown at all(just an empty hole). If I modify it into "f.ShowDialog();", the form f with the picture could be shown.
However here comes the third problem, which is the form f will be always there, my function "BuildTree();" isn't implemented at all!
The forth problem is if I add the line "Application.DoEvents();", it works quite fine, during the loading the form f with the picturebox will be shown and after the loading the f will disappear, but the picture in f is a gif, in this case the gif doesn't animate at all!
So anybody could help me solve the problem?
Here's my code of BuildTree function:
private void BuildTree(DirectoryInfo[] directoryInfo, TreeNodeCollection addInMe, TreeNode clicked)
{
for (int i = 0; i < directoryInfo.Length; i++)
{
var files = directoryInfo[i].GetFiles();
int length = files.Length;
clicked.Nodes.Add(directoryInfo[i].Name);
List<TreeNode> dateNode = new List<TreeNode>();
string[] allDates = new string[length];
try
{
for (int j = 0; j < length; j++)
{
allDates[j] = files[j].Name.Substring(11, 6);
}
}
catch (Exception e)
{ }
string[] date = allDates.Distinct().ToArray();
for (int k = 0; k < date.Length; k++) //From here to the end
{
// is my code loading file
dateNode.Add(clicked.Nodes.Add(date[i]));
for (int j = 0; j < length; j++)
{
// curNode.Nodes.Add(file.FullName, file.Name);
if (files[j].Name.Substring(11, 6) == date[i])
{
dateNode[i].Nodes.Add(files[j].FullName, files[j].Name);
}
}
}
foreach (DirectoryInfo subdir in directoryInfo[i].GetDirectories())
{
BuildTree(subdir, clicked.Nodes);
}
}
}
It depends on whether your BuildTree() method can be executed on background thread or not.
since you are passing references to properties of TreeView control I'm assuming that that code has to be executed on UI thread.
In this case th only thing I can suggest to you is call Application.DoEvents(); from within BuildTree() method, for example in a loop.
Also if you are making any long term calls to get data inside BuildTree() method, you should make these on background thread and synchronize with UI in any convenient way.
[EDIT]
I had a quick look at your BuildTree() method. I think in this case the best approach for you would be:
declare additional data structures to hold all data recuired to fill the TreeView.
Fill all the data on background (You can use BackgroundWorker for this)
here is a good question highlighting how get results from BackgroundWorker
Once all data is ready, create and add all nodes to TreeView. This also will take some time, but it has to be done on UI thread.
in order to keep UI responsive you can call Application.DoEvents() inside a loop where you will be adding new nodes to the tree
Code in treeView2_AfterSelect() would looks like this:
//...
f.Show();
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (ss, ee) =>
{
ee.Result = PrepareData(directory); // prepare all data required to build the Tree
}
bw.RunWorkerCompleted += (ss, ee) =>
{
BuildTreeByData(ee.Result, addInMe, clicked);
f.Close();
}
bw.RunWorkerAsync();
Add this line to your code, before calling f.Show():
f.Activated += (s, e) => BuildTree(directory, treeView2.Nodes, treeView2.SelectedNode);
// it's f.Shown for Windows Forms, Activated is for WPF
It subscribes an anonymous event handler to the OnShow event of your f form. In this handler you simply call your method.
If it doesn't work, you will have to replace the call to BuildTree here for a BackgroundWorker call, since it is possible that your BuildTree method access UI controls, and that is a big no-no. Call this code instead of f.ShowDialog:
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (ss, ee) =>
{
f.ShowDialog(this);
BuildTree(directory, treeView2.Nodes, treeView2.SelectedNode);
}
bw.RunWorkerCompleted += (ss, ee) => f.Close();
bw.RunWorkerAsync();
And change every access and modification to your controls in BuildTree like this:
this.Invoke((MethodInvoker) (() =>
{
// access you control here
}));

Moving picture in C#

I need to write a code which moves a picture1 to the top of the screen after a click of a button. After pictire1 reaches the top 20 pixels of the screen must become invisible and make picture2 visible. This is my wrong code:
private void button1_Click(object sender, EventArgs e)
{
int b = pictureBox1.Top;
for (int i = b; i < 20; i--)
{
pictureBox1.Top = i;
System.Threading.Thread.Sleep(20);
}
if (pictureBox1.Top < 20)
{
pictureBox1.Visible = false;
pictureBox2.Visible = true;
}
}
Any ideas how can it be fixed?
This seems wrong:
for (int i = b; i < 20; i--)
{
pictureBox1.Top = i;
System.Threading.Thread.Sleep(20);
}
This would loop while i < 20. From your code, however, one can see that if Top == 20 is reached, you'd like to show another picture. So I guess that should be i >= 20 and the if should be Top <= 20.
Also, you are not refreshing your display. Due to the loop and the Sleep, there will be no UI updates.
Add this, as Cobra_Fast suggests before the Sleep:
this.Invalidate();
this.Refresh();
To sum it up, the following should work (I've also slightly modified the code to make it clearer):
private void button1_Click(object sender, EventArgs e)
{
while (pictureBox1.Top >= 20)
{
pictureBox1.Top = pictureBox1.Top - 1;
this.Invalidate();
this.Refresh();
System.Threading.Thread.Sleep(20);
}
// Here you KNOW that the picture box is at y-position 20, so there's not need
// for the IF
pictureBox1.Visible = false;
pictureBox2.Visible = true;
}
The problem with the above code is that it blocks the UI. To keep it responsive, I'd use a timer as follows:
private void button1_Click(object sender, EventArgs e)
{
// Create a threaded timer
System.Timers.Timer animationTimer = new System.Timers.Timer();
animationTimer.Interval = 20;
animationTimer.AutoReset = false; // Only one Ping! We'll activate it if necessary
animationTimer.Elapsed += new ElapsedEventHandler(AnimationStep);
animationTimer.Start();
// Disable the button also, because we don't want another timer instance to
// interfere with our running animation
button1.Enabled = false;
}
Then, create the event that's called when the timer fires:
private void AnimationStep(object source, ElapsedEventArgs e)
{
// The following code needs to be executed in the context of the UI thread.
// We need to use this.Invoke in Forms or this.Dispatcher.Invoke in WPF
this.Invoke((Action)delegate()
{
// Move picture. Note that we don't need to update the display here
// because the UI thread gets time to do its work while the timer waits
// to fire below
if (pictureBox1.Top > 20)
pictureBox1.Top--;
// Show other picture maybe. I use <= here because initially, the
// position of the picture box may already smaller than 20.
if (pictureBox1.Top <= 20)
{
pictureBox1.Visible = false;
pictureBox2.Visible = true;
}
// Or let the timer fire again if we still need to animate
else
{
(source as System.Timers.Timer).Start();
}
}
}
This works as follows: A timer is created that fires once after 20ms. It then moves the picture up one pixel and then either shows the other picture if the animation is finished or starts the timer again for moving the picture up another pixel.
This keeps the UI responsive and still allows you to animate your picture. The downside is, the animation may not be as smooth as you might want it to be in case your windows is moved or other "work" needs be done by the UI thread.
What if initially b is greater than 20? The loop won't run because the condition in the loop is that i < 20. Because the loop is not ran, nothing will ever happen.
Consider changing the condition in your loop. You probably want the picture to move up, as you're reducing the Top-property. Let's say that initially the Top of pictureBox1 is 40. Following code will work:
while(pictureBox1.Top >= 20)
{
pictureBox1.Top--;
System.Threading.Thread.Sleep(20);
Invalidate();
Refresh();
}
Since the Top is now less than 20, the if-statement can be omitted and you can just call:
pictureBox1.Visible = false;
pictureBox2.Visible = true;
Complete code:
while(pictureBox1.Top >= 20)
{
pictureBox1.Top--;
System.Threading.Thread.Sleep(20);
Invalidate();
Refresh();
}
pictureBox1.Visible = false;
pictureBox2.Visible = true;
After the pictureBox1.Top assignment, call:
this.Invalidate();
this.Refresh();
Assuming you're working with WinForms.

C# Threading - an array of threads, where each thread contains a form with an image

I have an array of five threads. Each thread contains the same form, each form is put on to the screen in a different location (still working on that method :P).
I am trying to have each form load its contents (an image) before the other forms have finishing being placed. At the moment this works for the first form, but the others are blank or disappear :P
Originally each form would be placed but the method would need to finish before all the forms contents were displayed.
Any help would be appreciated, thanks :)
public partial class TrollFrm : Form
{
int number = 0;
public TrollFrm()
{
InitializeComponent();
startThreads();
}
private void TrollFrm_Load(object sender, EventArgs e)
{
}
private void TrollFrm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
public void startThreads()
{
Thread[] ThreadArray = new Thread[5];
for (int i = 0; i < 5; i++)
{
ThreadArray[i] = new Thread(new ThreadStart(createForm));
ThreadArray[i].Start();
}
}
public void createForm()
{
Form frm = new TrollChildFrm();
Random randomX = new Random();
Random randomY = new Random();
number++;
int xValue;
int yValue;
if (number % 2 == 0) //number is even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) + 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) - 200;
}
else //number is not even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) - 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) + 200;
}
frm.Show();
frm.Location = new Point(xValue, yValue);
Thread.Sleep(1000);
}
Your forms are not displaying correctly because they are not running on a thread with a message loop. The general rule is that all UI element accesses must occur on the main UI thread.
Since you have a call to Thread.Sleep(1000) I am going to assume that you want to wait 1 second between the initial display of each form. In that case I would use a System.Windows.Forms.Timer who's Tick event will call createForm directly. Enable the timer, let 5 Tick events come through, and then disable the timer. I see no need to create any threads at all.
The reason your forms aren't displaying is because you are running inside one method on the main UI thread. Instead, you could create a method that spawns a new form and launch that at certain intervals on another thread (making sure the form handling is done on the main UI thread). So you could do something like:
(Pseudo Code)
private const int TIME_THRESHOLD = 100;
int mElapsedTime = 0;
Timer mTimer = new Timer();
.ctor
{
mTimer.Elapsed += mTimer_Elapsed;
}
private void mTimer_Elapsed(...)
{
mElapsedTime++;
if (mElapsedTime >= TIME_THRESHOLD)
{
mElapsedTime = 0;
SpawnForm();
}
}
private void SpawnForm()
{
// Make sure your running on the UI thread
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(SpawnForm));
return;
}
// ... spawn the form ...
}
This is just an example of what I was proposing - it would not look exactly like this in the code, but this should give you an idea of the execution steps.
I would suggest to use Thread.Sleep(1000) in this manner
Caller section
for (int i = 0; i < 5; i++)
{
ThreadArray[i] = new Thread(new ThreadStart(createForm));
ThreadArray[i].Start();
}
Thread.Sleep(1000);
Also in the method that executing the work for the thread.
while(!something)
{
Thread.Sleep(1000)
}

How do I implement a progress bar in C#?

How do I implement a progress bar and backgroundworker for database calls in C#?
I do have some methods that deal with large amounts of data. They are relatively long running operations, so I want to implement a progress bar to let the user know that something is actually happening.
I thought of using progress bar or status strip label, but since there is a single UI thread, the thread where the database-dealing methods are executed, UI controls are not updated, making the progress bar or status strip label are useless to me.
I've already seen some examples, but they deal with for-loops, ex:
for(int i = 0; i < count; i++)
{
System.Threading.Thread.Sleep(70);
// ... do analysis ...
bgWorker.ReportProgress((100 * i) / count);
}
private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = Math.Min(e.ProgressPercentage, 100);
}
I'm looking for better examples.
Some people may not like it, but this is what I do:
private void StartBackgroundWork() {
if (Application.RenderWithVisualStyles)
progressBar.Style = ProgressBarStyle.Marquee;
else {
progressBar.Style = ProgressBarStyle.Continuous;
progressBar.Maximum = 100;
progressBar.Value = 0;
timer.Enabled = true;
}
backgroundWorker.RunWorkerAsync();
}
private void timer_Tick(object sender, EventArgs e) {
if (progressBar.Value < progressBar.Maximum)
progressBar.Increment(5);
else
progressBar.Value = progressBar.Minimum;
}
The Marquee style requires VisualStyles to be enabled, but it continuously scrolls on its own without needing to be updated. I use that for database operations that don't report their progress.
If you can't know the progress you should not fake it by abusing a progress bar, instead just display some sort of busy icon like en.wikipedia.org/wiki/Throbber#Spinning_wheel Show it when starting the task and hide it when it's finished. That would make for a more "honest" GUI.
When you perform operations on Background thread and you want to update UI, you can not call or set anything from background thread. In case of WPF you need Dispatcher.BeginInvoke and in case of WinForms you need Invoke method.
WPF:
// assuming "this" is the window containing your progress bar..
// following code runs in background worker thread...
for(int i=0;i<count;i++)
{
DoSomething();
this.Dispatcher.BeginInvoke((Action)delegate(){
this.progressBar.Value = (int)((100*i)/count);
});
}
WinForms:
// assuming "this" is the window containing your progress bar..
// following code runs in background worker thread...
for(int i=0;i<count;i++)
{
DoSomething();
this.Invoke(delegate(){
this.progressBar.Value = (int)((100*i)/count);
});
}
for WinForms delegate may require some casting or you may need little help there, dont remember the exact syntax now.
The idea behind reporting progress with the background worker is through sending a 'percent completed' event. You are yourself responsible for determining somehow 'how much' work has been completed. Unfortunately this is often the most difficult part.
In your case, the bulk of the work is database-related. There is to my knowledge no way to get progress information from the DB directly. What you can try to do however, is split up the work dynamically. E.g., if you need to read a lot of data, a naive way to implement this could be.
Determine how many rows are to be retrieved (SELECT COUNT(*) FROM ...)
Divide the actual reading in smaller chunks, reporting progress every time one chunk is completed:
for (int i = 0; i < count; i++)
{
bgWorker.ReportProgress((100 * i) / count);
// ... (read data for step i)
}
I have not compiled this as it is meant for a proof of concept. This is how I have implemented a Progress bar for database access in the past. This example shows access to a SQLite database using the System.Data.SQLite module
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;
using(SQLiteConnection cnn = new SQLiteConnection("Data Source=MyDatabase.db"))
{
cnn.Open();
int TotalQuerySize = GetQueryCount("Query", cnn); // This needs to be implemented and is not shown in example
using (SQLiteCommand cmd = cnn.CreateCommand())
{
cmd.CommandText = "Query is here";
using(SQLiteDataReader reader = cmd.ExecuteReader())
{
int i = 0;
while(reader.Read())
{
// Access the database data using the reader[]. Each .Read() provides the next Row
if(worker.WorkerReportsProgress) worker.ReportProgress(++i * 100/ TotalQuerySize);
}
}
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Notify someone that the database access is finished. Do stuff to clean up if needed
// This could be a good time to hide, clear or do somthign to the progress bar
}
public void AcessMySQLiteDatabase()
{
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.DoWork +=
new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(
backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged +=
new ProgressChangedEventHandler(
backgroundWorker1_ProgressChanged);
}
This will Helpfull.Easy to implement,100% tested.
for(int i=1;i<linecount;i++)
{
progressBar1.Value = i * progressBar1.Maximum / linecount; //show process bar counts
LabelTotal.Text = i.ToString() + " of " + linecount; //show number of count in lable
int presentage = (i * 100) / linecount;
LabelPresentage.Text = presentage.ToString() + " %"; //show precentage in lable
Application.DoEvents(); keep form active in every loop
}
You have to execute the process from a thread, and from the thread you invoke the progress bar and change its value, maybe this example helps you
public void main()
{
int count = 20;
progressbar.Maximum = count;
progressbar.Value = 0;
new Thread(() => Work(progressbar, count)).Start();
}
public static void Work(ProgressBar progressbar, int count)
{
for (int i = 0; i <= count; i++)
{
Thread.Sleep(70);
// ... do analysis ...
Application.Current.Dispatcher.Invoke(new Action(() =>
{
progressbar.Value = i;
}));
}
}

Categories

Resources