Operations in background with UI reaction - c#

I need to make a sorting application that displays the current operations.
I've done it like that:
I have collection of ints. Inside it, I have sorting algorithms and event 'step' that takes two arguments 'operation' eg. compare, permutation etc. and int[] of elements that I do something with.
I want to change the item background in ListView if sorting is doing something with specific items. '250 ms blink'. Something like that:
listView1.Items[1].BackColor = Color.LightGreen;
listView1.Items[2].BackColor = Color.LightGreen;
Thread.Sleep(250);
for (int i = 0; i < args.Length; i++)
{
listView1.Items[i].BackColor = Color.White;
}
But when I'm trying to start sorting, the UI is freezing and after couple of seconds it is displayed as a SortedCollection.
My question is:
How do I show 'live' actions on UI during sorting?

Instead of Thread.Sleep(250) use await Task.Delay(250). To make this possible you need to mark your method as async

Related

Wait until task has completed within a loop before executing next line of code

I am using Visual C# 2013 to create a win-forms applications. I have a loop which takes up to a minute to complete due to a large calculation having to be carried out on many rows of data within a table, therefore whilst the user waits I display a 'loading...' form.
On this form I wish to display a count down of the number of rows, so the user can see how many rows of the data there are left to be calculated, however the label with this number on will not update as everything 'freezes' until the loop has finished.
System.Windows.Forms.Form f = System.Windows.Forms.Application.OpenForms["LoadingForm"];
int DataRowsRemaining = TotalRowCount;
for (int i=0; i<=TotalRowCount; i++)
{
//CALCULATION CODE
((LoadingForm)f).label1.Text = Convert.ToString(DataRowsRemaining--);
}
This code does not allow the label to update during the loop. Using, Application.DoEvents(); after the label does allow it to be updated but this also refreshes every other label on the form which significantly slows down the calculation, therefore I think I need to allow this one line of code to be carried out on a separate thread.
Due to my knowledge being limited on the subject, could anyone advise me whether the multi-threading technique would be the best way to solve this issue, and if so any advice on how I could code this as I have been struggling to understand online examples of multi-threading.
Thanks for your time, Aaron.
Simplest way would be
await Task.Run(() => { /* CALCULATION CODE */ });
private async void Calculation()
{
for (int i = 0; i <= TotalRowCount; i++)
{
await Task.Run(() => { /* CALCULATION CODE */ });
((LoadingForm)f).label1.Text = Convert.ToString(DataRowsRemaining--);
}
}
There is an example here in MSDN on how to use .Invoke(). However, L.B's answer is probably much simpler.

C# - updating label while adding items to ListView

I have a ListView which I populate with a lot of items, over 3000. This can take up to 15 seconds.
Every time I add an item I want to update a label stating how many items have been added so far.
To do so I use this code:
foreach (FileInfo f in dir.GetFiles("*.*", SearchOption.AllDirectories))
{
DateTime dt = GetDateTakenFromImage(Path.Combine(f.Directory.ToString(), f.Name));
count++;
labelLoadedLeft.Text = "Loading " + count + " files so far";
ListViewItem lSingleItem = lv.Items.Add(f.Name);
lSingleItem.SubItems.Add(dt.ToString("dd MMMM yyyy"));
lSingleItem.Tag = Path.Combine(f.Directory.ToString(), f.Name);
}
Unfortunately the label does not show until all items have been loaded.
I understand this has to do with the fact that I am doing a lengthy operation on thr UI thread and that I should probably be using a backgroundworker to do the work.
Does anyone know of good and simple examples on how to use background worker. What I have found so far is too complicated for me or too convoluted.
Thank you
Crouz
If you only want your Label to update, you should update it.
labelLoadedLeft.Text = "Loading " + count + " files so far";
labelLoadedLeft.Update();
Which version of VS/C# do you use? With VS2012/C#5.0 you could take advantage of the new "await" feature. It makes code easy to read and updating the UI can be done without invoke etc
You can do it with a BackgroundWorker, here's an example, http://dotnetforum.net/topic/34729-how-to-cancel-backgroundworker-during-getfiles/.
However, the UI will never show anything until the you get a list of all files. And as you said this is slow.
Use the EnumerateFiles method, http://msdn.microsoft.com/en-us/library/dd383458(v=vs.100).aspx, which returns one file at a time.
A background worker is most easily handled via the TPL, presuming you're working with .NET 4.0. You can start a worker in the background using code that looks like this:
Task.Factory.StartNew( () =>
{
// Background Worker Stuff goes here
}, TaskCreationOptions.LongRunning);
You can then put your worker's job in another class/function, and have it yield return its results from DoWork(), giving you an IEnumerable<T> of whatever it's returning. Using your foreach loop over that like so:
foreach(var item in DoWork())
{
// Update UI
}
Will mean you can update the UI as results come back. Yield return will allow you to handle items before the entire enumerable returns. Be careful, though - yield return implicitly sets up a state machine inside your program, so unless you need functionality like this it can be very wasteful to use this idiom.
You may not need it. Use Begin/EndUpdate on the ListView.
http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.beginupdate.aspx
This will prevent drawing of the items until they're all loaded. You won't be able to maintain a count, but I don't really see the benefit of that at all, especially if this makes it too fast to matter.

best way to program a progress bar for many methods

Say I have a button: btnExecute
This button executes all these methods:
doAction1();
doAction2();
doAction3();
doAction4();
Each of these actions takes a couple of seconds.
How would I go about updating a progress bar as each of these methods are run?
I know I could go into each of them and just add pbExecuteProgress.value = 10 for example but I feel like there must be a better way to do this.
I also do not want to do something like this:
doAction1();
pbExecuteProgress.value = 30
doAction2();
pbExecuteProgress.value = 60
doAction3();
pbExecuteProgress.value = 80
doAction4();
pbExecuteProgress.value = 100
Is there ANY way I create a progress bar that goes up to 100 in value and is = to the progress of a method??
var actions = new List<Action> {doAction1, doAction2, doAction3, doAction4};
foreach(var action in actions)
{
action();
progressBar.Value += (progressBar.Maximum - progressBar.Minimum) / actions.Count;
}
if you wanted to customize the progress values:
var actions = new Dictionary<Action, int>
{
{doAction1, 30},
{doAction2, 30},
{doAction3, 20},
{doAction4, 20},
};
progressBar.Minimum = 0;
progressBar.Maximum = actions.Select(kvp=>kvp.Value).Sum();
progressBar.Value = 0;
foreach(var action in actions)
{
action.Key();
progressBar.Value += action.Value;
}
Declaration and creation of the collection of actions does not have to happen just before you loop through it. In fact, a strength of this pattern (a form of the Strategy pattern) is that new Actions can come from anywhere, both inside the current class and out.
When you "nest" progress, the outer method has to estimate how long each subroutine will take to execute, and divide up its 100% among the subroutines.
You can either do this arbitrarily, i.e. method one is 40%, method two is 25%, etc, or you can do a"dry run" to decide how much work each method will do. For example, if each method processes a number of files, the dry run would count the files without actually processing them, and you could then use the file counts for each method to allocate the range of the progress bar that apples to each method.
The dry run approach gives a more accurate result, but the pre processing required can take quite a long time, and thus make the overall task slower.
Once you have the range for each subroutine you can pass in their starting and ending percentages, and they can advance the progress appropriately.
A neat way to handle this is to create a progress manager class that deals with all the subtask scaling, which makes if easy to nest a whole subtree of calls, and pass only one object around them to handle the progress display.
If you really want to do it yourself, I'd suggest timing each one of the statements inside of each method as well as the entire method, throw all the times into an array, convert them to a percentage, and write em to a text file or something. Rinse and repeat, average em up, and then you'll have to add a bunch of pbExecuteProgress.value = X statements. I know you said you didn't wanna do that, but at least this way it'd be a really accurate representation of the progress.
Just a thought.
Also, I'm fairly sure there are third party tools that'll do this kind of thing for you. However, it will be inherently impossible for them to be as accurate as the method above.

c# update listbox without 'lag'

I've been searching the web for a way to do this without much success, so here's the question.
How do add items to a listbox in a separate thread, so that it doesn't freeze up the ui?
There are roughly 5-15k items each time added to the listboxes, and it freezes the ui for 5-12 seconds each time.
The form has 4 listboxes, the information for these listboxes is first created, and added to a 2D array (doing it this way makes it easier to keep track of all information that belongs together in 1 row). after which i loop over that 2D array, adding the 4 columns in 1 row to it's respective listbox.
eg.
for (int n = 0; n < 7500; n++)
{
listBox1.Items.Add(itemList[n, 0].ToString());
listBox2.Items.Add(itemList[n, 1].ToString());
listBox3.Items.Add(itemList[n, 2].ToString());
listBox4.Items.Add(itemList[n, 3].ToString());
}
As stated before, how to use a thread other than the UI to update these listboxes to prevent unnecessary freezing of the ui
You can take a different approach and use a virtual ListView instead. When a ListView is "virtual", you are responsible for maintaining item lists and telling ListView what to display on paint events. This way you can update your lists in any thread-safe way you'd like and ListView will only ask of you "what to draw on screen" rather than a full list of items. That's actually the preferred method when obtaining list of all items is very costly.
See the documentation on VirtualMode:
http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.virtualmode.aspx
UPDATE: Since you mentioned that you need it for debugging I also suggest you to use debug output (Debug.WriteLine()) which could be more suitable for the job. It's optimized, it's thread safe, it doesn't block anything but itself and the best part is it doesn't affect performance of release builds.
And in case you need a more performant output you can redirect your debugging output to anywhere you like.
Use BeginUpdate() and EndUpdate()
http://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.beginupdate.aspx
That's inherently impossible.
You can only manipulate the UI from the UI thread. (UI is not thread-safe)
You can make it faster by calling BeginUpdate() and EndUpdate(), and you can make it even faster (but harder) by using a ListView in virtual mode.
However, you should not display 15,000 items in a lsitbox.
Such a listbox would be useless in actual use.
listBox1.BeginUpdate();
listBox2.BeginUpdate();
listBox3.BeginUpdate();
listBox4.BeginUpdate();
for (int n = 0; n < 7500; n++)
{
listBox1.Items.Add(itemList[n, 0].ToString());
listBox2.Items.Add(itemList[n, 1].ToString());
listBox3.Items.Add(itemList[n, 2].ToString());
listBox4.Items.Add(itemList[n, 3].ToString());
}
listBox1.EndUpdate();
listBox2.EndUpdate();
listBox3.EndUpdate();
listBox4.EndUpdate();
This will delay drawing until all items have been added, so it should be faster.
You should try to use BeginUpdate/EndUpdate methods:
listbox1.BeginUpdate();
// Adds 5K items
listbox1.EndUpdate();
You can significantly speed up this process by preventing the ListBox from repainting after every add by wrapping the for loop in:
listBox1.BeginUpdate();
listBox2.BeginUpdate();
listBox3.BeginUpdate();
listBox4.BeginUpdate();
for (int n = 0; n < 7500; n++)
{
listBox1.Items.Add(itemList[n, 0].ToString());
listBox2.Items.Add(itemList[n, 1].ToString());
listBox3.Items.Add(itemList[n, 2].ToString());
listBox4.Items.Add(itemList[n, 3].ToString());
}
listBox1.EndUpdate();
listBox2.EndUpdate();
listBox3.EndUpdate();
listBox4.EndUpdate();
I just want to bring everyones answers together. You should really be updating items in your GUI thread or you may get unexpected results. To guarantee that the code is operating in the GUI thread and your list isn't repainting itself every Add() you need the BeingUpdate() and EndUpdate() pair, as others have posted, but to run that in the GUI thread use the BeingInvoke(), which simply puts the task on the "GUI thread queue" ready for consumption. BeingInvoke() will return immediate but your request will be put on the queue.
BeingInvoke() API Doc.
http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx
A good discussion on BeginInvoke() and why it is used.
BeginInvoke((MethodInvoker)delegate
{
listBox1.BeginUpdate();
listBox2.BeginUpdate();
listBox3.BeginUpdate();
listBox4.BeginUpdate();
for (int n = 0; n < 7500; n++)
{
listBox1.Items.Add(itemList[n, 0].ToString());
listBox2.Items.Add(itemList[n, 1].ToString());
listBox3.Items.Add(itemList[n, 2].ToString());
listBox4.Items.Add(itemList[n, 3].ToString());
}
listBox1.EndUpdate();
listBox2.EndUpdate();
listBox3.EndUpdate();
listBox4.EndUpdate();
});

how to increase speed of my execution

i am creating project in c#.net. my execution process is very slow. i also found the reason for that.in one method i copied the values from one list to another.that list consists more 3000values for every row . how can i speed up this process.any body help me
for (int i = 0; i < rectTristrip.NofStrips; i++)
{
VertexList verList = new VertexList();
verList = rectTristrip.Strip[i];
GraphicsPath rectPath4 = verList.TristripToGraphicsPath();
for (int j = 0; j < rectPath4.PointCount; j++)
{
pointList.Add(rectPath4.PathPoints[j]);
}
}
This is the code slow up my procees.Rect tristirp consists lot of vertices each vertices has more 3000 values..
A profiler will tell you exactly how much time is spent on which lines and which are most important to optimize. Red-gate makes a very good one.
http://www.red-gate.com/products/ants_performance_profiler/index.htm
Like musicfreak already mentioned you should profile your code to get reliable result on what's going on. But some processes are just taking some time.
In some way you can't get rid of them, they must be done. The question is just: When they are neccessary? So maybe you can put them into some initialization phase or into another thread which will compute the results for you, while your GUI is accessible to your users.
In one of my applications i make a big query against a SQL Server. This task takes a while (built up connection, send query, wait for result, putting result into a data table, making some calculations on my own, presenting the results to the user). All of these steps are necessary and can't be make any faster. But they will be done in another thread while the user sees in the result window a 'Please wait' with a progress bar. In the meantime the user can already make some other settings in the UI (if he likes). So the UI is responsive and the user has no big problem to wait a few seconds.
So this is not a real answer, but maybe it gives you some ideas on how to solve your problem.
You can split the load into a couple of worker threads, say 3 threads each dealing with 1000 elements.
You can synchronize it with AutoResetEvent
Some suggestions, even though I think the bulk of the work is in TristripToGraphicsPath():
// Use rectTristrip.Strip.Length instead of NoOfStrips
// to let the JIT eliminate bounds checking
// .Count if it is a list instead of array
for (int i = 0; i < rectTristrip.Strip.Length; i++)
{
VertexList verList = rectTristrip.Strip[i]; // Removed 'new'
GraphicsPath rectPath4 = verList.TristripToGraphicsPath();
// Assuming pointList is infact a list, do this:
pointList.AddRange(rectPath4.PathPoints);
// Else do this:
// Use PathPoints.Length instead of PointCount
// to let the JIT eliminate bounds checking
for (int j = 0; j < rectPath4.PathPoints.Length; j++)
{
pointList.Add(rectPath4.PathPoints[j]);
}
}
And maybe verList = rectTristrip.Strip[i]; // Removed 'VertexList' to save some memory
Define variable VertexList verList above loop.

Categories