I've got a "Loading Progress" WPF form which I instantiate when I start loading some results into my Main Window, and every time a result is loaded I want the progress bar to fill up by x amount (Based on the amount of results I'm loading).
However what happens is that the Progress bar in the window stays blank the entire time, until the results have finished loading, then it will just display the full progress bar.
Does this need threading to work properly? Or is it just to do with the way I'm trying to get it to work?
//code snippet
LoadingProgress lp = new LoadingProgress(feedCount);
lp.Show();
foreach (FeedConfigGroup feed in _Feeds) {
feed.insertFeeds(lp);
}
//part of insertFeeds(LoadingProgress lbBox)
foreach (Feeds fd in _FeedSource) {
lpBox.setText(fd.getName);
XmlDocument feedResults = new XmlDocument();
feedResults.PreserveWhitespace = false;
try {
feedResults.Load(wc.OpenRead(fd.getURL));
} catch (WebException) {
lpBox.addError(fd.getName);
}
foreach (XmlNode item in feedResults.SelectNodes("/rss/channel/item")) {
//code for processing the nodes...
}
lpBox.progressIncrease();
}
If more code is needed let me know.
Consider accessing the progressbar from the external thread thru a delegate asynchronously using the ProgressBar's Dispatcher.Invoke.
This post might be helpful.
I suggest you to use another thread to do the processing. The progress bar is filled at the end, so you didn't make a mistake on its programming.
In general, you should avoid to do processing in the user interface thread.
So, how many feeds and how many items? I'll wait for you to count them in order to set the total length of the progress bar.
...
What was that? You wouldn't know the total until after most of the work is already done? Well, sounds like the progress bar isn't the correct control to use.
You're doing (at least what should be) asynchronous work here. Definitely do it in a worker thread. Definitely let the user know work is going on in the background. But don't use a progress bar. You can't know exactly what point in the process you are at and how much longer you have to go until all the long-lasting processes have completed. Most of your users will see that your progress bar as the lie it is and will laugh at your suck.
Just use the standard "work is going on in the background" fadey-circle-thingy on your RSS feed box (an Adorner would work nicely) and be done with it.
Using this video I managed to get it working, Dispatch.BeginInvoke (Except for one which needed to be Dispatcher.Invoke) was the way to go. If anyone wants the final code let me know and I can post it up.
Related
I have a simple foreach loop that I would like to paralellize, here's my code (not paralellized for now):
foreach (string filename in ofdmulti.FileNames)
{
img.Add(new DicomImage(filename)); // fill images
Progress_Bar_Loading_Images.PerformStep();
}
Now, my big problem is the progressbar.. I get an error because it seems I can't update the progressbar on another thread than the one that got created..
any hints?
Thanks!
Use Background Worker. It has built in support for doing cross-thread UI calls so you don't have to do anything special for it. Plus, it has events built in for updating progress bars. This tutorial walked me through it when I first needed to do exactly that.
sorry if this is a silly question, I am new to C#, so please give me a break.
I am working on Revit API. currently, Revit API doesn't support multi-threading operations.
my question is how to stop a loop without calling a new thread?
I am trying to get a snapshot and I am waiting for the user to pick a snap, so I put an infinite loop till the condition meets
while (!Clipboard.ContainsImage()) //loop till user get a clipboard image
{
}
but what if I want to abort this???
I have tried
private void Abort_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
abort = true;
}
}
but this method requires threading ....any suggestions!!
You want to look into asynchronous processing patterns in Revit - check for instance The Building Coders description of IExternalEvent.
It might take a little while to wrap your head around it, but let me try to explain:
Split your code up into two parts: The first part runs up until the moment you ask the user to pick a snap (I'm assuming this happens in another application?). In a separate thread, poll the clipboard (or register your application as a clipboard viewer) in your while loop. Don't forget to Sleep() while you're polling! As soon as your polling thread finds a picture, create an instance of an IExternalEvent subclass and post it to Revit. When Revit has some spare time, it will execute the Execute method, passing in a UIApplication that you can use to do the rest of your code.
Revit doesn't let you access it's API from multiple threads at the same time, but during the Execute method of an IExternalEvent subclass, you are guaranteed to be in the correct thread for running code.
You can also look into the OnIdling event - basically, this gets called each time Revit has some spare time too. So instead of using a while loop in a separate thread, you could just place your clipboard checking code in the event handler for the OnIdling event and create a mechanism (a flag) to tell you wether you are currently waiting for a snap or not...
I have a big project (30ish developed classes) and I want to make a loading bar for it. I have a current progress and total progress bars. I also have to roughly describe what is happening during the current process.
The way that I did it is manually (haters gonna hate) go through the most greedy process and did estimations of how long it is gonna take (when it is a for loop, just do step ups each iteration).
I read that Background_Worker would be much more smoother, but as I read on, it appeared to me that I still do have to go to every chunk of code and say that I want to increment the progress bar (The idea that I have to do it do describe the process made sense to me).
So my question was: is there a way to sort of encapsulate your method in a "block", which would automatically allocate the progress bar times? Or is there a more efficient way to do what I'm doing?
The best way would be to put your main processing in a different thread to NOT overload your GUI so it doesn't freeze up (user frustration) and then do your progress bar in the GUI thread (or make another thread for the bar, too). All depends on the preference.
But NEVER!! Freeze up the UI. The users just think it is dead and try to force close it.
is there a way to sort of encapsulate your method in a "block", which
would automatically allocate the progress bar times?
No, progress bar is for showing a progress, so you have to set the start, end and current state values form outside (from the caller), because only caller knows what is it going to execute and have, potentially, control over it.
Yes, it is possible, if you visualize infinit bar, that does not provide to a user some quantitative information about action executing, but informs to him, that something is going on. You also can provide some text description, that changes based on current action, so user can see that "something is going on there".
There is nothing worse from UX point of view, then leaving user uniformed, confused in front of the UI that is doing something, which is not clear.
So the both approaches are good, imo.
Perhaps a background worker with the progress bar. Use a global variable to store the progress.
public class SomeClass
{
public int Progress { set; get; }
public void Method1()
{
...
Progress++;
}
public void Method2()
{
...
Progress++;
}
...
}
As each method is called, increment the progress and call the background worker to report progress.
I know there are better solutions to this but this is just an idea.
I am having issues on how to get around the following problem.
I have a class which which allows me to dynamically update and display a graph on a form. In order to update the values of the graph I have a method within the class of the form. I pass in the value to update the graph with to this method. Here is a high level example of what I am trying to do:
class GUICLass : Form {
//Code for drawing chart etc all here
public updategraphWithNewValue(double value){
// Code to update the graph
}
}
My other class is as follows:
class ValueProviderForGraph{
GUIClass graphForm = new GUIClass();
public calculateValuesAndPlot(){
for(int i = 0; i < 4000; i++){
graphForm.updategraphWithNewValue(i);
graphForm.update();
}
}
}
Now the issue I get from the above is that the form freezes while this operation is taking place. How could I go about getting around this, any help or advice would be much appreciated. I hope this high level example has enough information, if not please do let me know and I shall try and explain myself better.
Thanks.
Look into using BackgroundWorker. Its event-oriented interface should get you up and running quickly.
You can only update your form's controls from the thread that the control was originally created on.
If you are trying to update it from a different thread, you must marshal that call. There are numerous approaches on the web. My personal favorite (for WinForms) is the following:
https://stackoverflow.com/a/709846/141172
UPDATE
After re-reading your question at the urging of #StenPetrov, I suspect that you do not have a cross-thread issue after all, but that the UI thread is simply not processing messages while it updates the graph (this would cause the freezing during the operation).
If the UI thread is busy updating the graph, you will get that behavior. However, it looks like you are causing the graph to do an unnecessary update 3999 times. Try moving the line
graphForm.update();
outside of your for loop.
While I don't know exactly how your graph control works, I suspect the call to update() causes the entire graph to be re-rendered. You should only do that after all new data points have been added.
Do you need to update the UI often or not?
If you don't have to update the UI often, such as loading a large graph for viewing, then BackgroundWorker will do.
If you need the UI updated frequently you have to (a) make your graph calculations independent of UI, (b) run the graph calculations in a separate thread and (c) after the update is calculated use Form.Invoke(...) to update the UI
I started programming just few month ago so I am a pure beginner
but I needed a math app with Heavy probability calculation and an UI to view/interact so I searched around and found C#.net was the best way... fantastic power...
It will help me a lot to progress if I am able do this :
Wpf window with textbox, in textbox a number is printed each time the calculation is done but the Ui should respond everytime
I tried to do it using latest net 4.5 because the app need to be fast (so use the most recent tech and not timer or background task)
and it work but the Ui is stuck and cannot move (because of my bad access to the text box I think)
If guys could help me it will be great and I thank you all because I learned a lot with your posts!
Here is my wrong newbie code
private Random rng;
public MainWindow()
{
rng = new Random();
InitializeComponent();
Task.Run((Func<Task>) Calc);
}
private async Task Calc()
{
while (true)
{
textBox1.Dispatcher.Invoke
(DispatcherPriority.Normal
, new Action(delegate()
{
textBox1.Text = rng.NextDouble().ToString();
}
)
);
}
}
You're tightlooping, admittedly in a non-UI-thread, but adding a bazillion delegates to invoke in the UI thread... so your UI is just too busy.
All your work is basically going on in the UI thread at the moment - you're not even computing rng.NextDouble() in the background thread.
Also note that you've got an async method without an await expression, which should have triggered a compiler warning - you should take heed of that.
You say you don't want to use a "background task" - but that's exactly what you are doing by calling Task.Run.
Now I'm assuming your real code doesn't actually just need to create random numbers. What does your real calculation code look like, and which thread does it occur in?