Listbox not completely vanishing on hide - c#

I've got a simple method that does this:
private void searchButton_Click(object sender, EventArgs e)
{
searchResultsBox.Hide();
doSomething();
}
searchResultsBox is a listbox, and when I call its Hide method, it doesn't actually completely vanish until 'doSomething' finishes processing. It kind of leaves artifacts (in fact you can still see any part of the box that had an empty form surface behind it.
If I comment out 'doSomething', it vanishes promptly.
Any ideas on how to fix this? It's just a bit ugly.

You could try calling this.refresh() after calling searchResultsBox.Hide();

You should not do significant work in the GUI event thread, as it will cause the UI to freeze up while it is busy running your event handling code. It is a good practice to do any long-running tasks in another thread, either by signaling another already-running thread to do the work or by starting a new thread on the spot.
new Thread(new ThreadStart(doSomething)).Start();

Sound like doSomething is process intensive and blocking the GUI thread, not sure why it would not finishing hiding the list before executing doSomething.
I would try putting doSomething in to a separate thread.

The separate thread or background worker process is the best answer. You can also try calling Application.DoEvents(). That seems to work at times for this specific issue although I'm not in favor of using that call often.

Related

Can't pass UI controls' values as parameters to method inside Task.Factory.StartNew

I'm kind of in a learning process of multi-threading, so while I was playing around with Task class I notice some strange (for me) behavior with calling Task.Factory.StartNew method. I was doing some example in WPF application, where I just tried to call a method from Task on button click and what I have done is this:
Task.Factory.StartNew(() => OrderTickets(numberOfTicktes, cbMovieName.Text));
However the method OrderTickets was never called. Then I changed my code like this:
string movieName = cbMovies.Text;
Task.Factory.StartNew(() => OrderTickets(numberOfTicktes, movieName ));
After this change my method "OrderTickets" was called as I expected. My question here is why I can not use values of UI controls, like I tried with my combobox, directly inside of Task StartNew method? My guess, this is because UI controls are hold by the UI thread but not quite sure about it. Can anyone explain to me what really happens here? Could you point me to Microsoft documentation describing this?
If your code could speak, this is what you are doing:
"I am the main thread. Hey scheduler can you please do this work for me using a thread from the pool?"
() => OrderTickets(numberOfTicktes, cbMovieName.Text)
Main thread is now free and sometime later (or immediately) a pool thread picks up this work to do it and notices this:
cbMovieName.Text
So it tries to communicate with cbMovieName but the thread (in your case main thread or UI thread) intervenes and says:
"Hey pool thread, why are you trying to communicate with one of my controls without asking me? Go away!!! (As he rolls his eyes)"
Exception is thrown on the pool thread but not bubbled up. Therefore, it seems to you like it was never called but all the above happened.
In the other case where you have this:
string movieName = cbMovies.Text;
() => OrderTickets(numberOfTicktes, movieName)
It will work because the pool thread does not need any UI control.
It isn't immediately obvious, but the issue is that you are running into two issues - and they way they interact is a bit confusing.
Issue 1 - you can't access controls outside of the UI thread.
Issue 2 - StartNew doesn't bubble up exceptions in the way you are expecting it to. ContinueWith may assist with this.
The net result is it looks to you like the call failed without throwing an exception.

Clarification on updating GUI from a separate Thread using an anonymous method

I've found what looks like a very simple solution to my current situation.
My current situation is that I want to do some I/O-heavy operations on a new Thread, so that I do not bog down my GUI Thread. I have a function written, as a member of my Form, that does these I/O operations already, but running it on the GUI Thread really makes the application a pain to use. So my plan was to just run this function in a new Thread. So, I created a Thread variable, in my form, and am trying to get it to use that function as the ThreadStart parameter. It does not seem to like it, though.
I found an elegant looking solution, as a response to another thread, here.
///...blah blah updating files
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
someLabel.Text = newText; // runs on UI thread
});
///...blah blah more updating files
From the looks of that response, I could run this function in a new Thread and then use an anonymous function to update my Form when the Thread has finished its calculations. I'm just not good enough to fill in the blanks from that response, though.
Everything I seem to read about Threads says that my ThreadStart function needs to be a static method in a new class. That response seems to suggest that I can do it within my Form class though, so that the this reference still references my Form instance. Otherwise, if my ThreadStart parameter were a different class, I'd have to pass in references to the Form instance, and that seems like more code, right?
Would anybody mind helping me fill in the context for that response? Thanks in advance!
There are a lot of ways you can do this. A very simple, straightforward one that's been around for a number of versions is to use the BackgroundWorker. It is designed for exactly this case. It has a DoWork method that runs in a background thread, and a Completed event that is fired after the work is done which runs in the UI thread (so you don't need to call invoke or anything to update the UI with the results). It even has support built in for reporting progress (the report progress event also runs in the UI thread) so you can easily update a progress bar or status text.
MSDN has some examples as well, and you can find lots more through some simple searches.
Another option, made available through C# 4.0, is to use Tasks. You can start a new task which will be run in a background thread, and then you can add a continuation which will be in the UI thread.
Here is a simple example:
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() => doStuffInBackground())
.ContinueWith(task => updateUI(), TaskScheduler.FromCurrentSynchronizationContext());
}
private void updateUI()
{
throw new NotImplementedException();
}
private void doStuffInBackground()
{
throw new NotImplementedException();
}
You can of course do whatever you want in the actual lambdas that I have there, or you could even remove the lambdas and put methods in there directly as long as you ensure the signatures are correct. You could also continue chaining these continuations if you wanted, allowing you to, for example, to task 1, update a label, then do task 2, update a label, etc. The main disadvantage is that it's not good at updating a progress bar frequently inside of a loop, the way a BackgroundWorker can.

C# Method Statements Not executing in correct order

I seem to have a problem executing commands in the correct order, I have a method in my Program:
private void GenerateButton_Click(object sender, EventArgs e)
{
Statuslabel.Text = "Working...";
LongMethod();
//Call to another Method of another class which takes 15-20 seconds to execute
Statuslabel.Text = "Done";
}
the problem seems to be that instead of assigning "Working" to the status label and THEN calling the LongMethod, the Program seems to execute LongMethod() first, and then it changes Status Label's text to "Working" for a split second and then immediately changes it to "Done".
Oh, and the UI is locked up during the LongMethod() execution, because the Program is SingleThreaded.
I tried threads earlier, but for the life of me I couldn't get the syntax right, I tried:
Thread MyThread = new Thread(LongClass.LongFunction);
Thread MyThread = new Thread(new ThreadStart(LongClass.LongFunction));
Where LongClass is the class which contains LongFunction as a static method.
I will check out the background worker now.
You should execute LongMethod on another thread so that the UI thread doesn't block while it's running.
Remember, updating the UI is running code just like anything else. While your long-running method is running, that thread is not doing any of the tasks necessary to redraw the user interface. Changing a UI element does not stop everything and re-draw it because suppose you changed a thousand UI elements; you wouldn't expect a redraw after each one; you'd expect them all to happen at once, after you'd made all the changes.
Long story short, if you want to refresh the UI after the update but before the long-running code -- that is, you don't care about hanging the UI but you at least want it to update -- then insert a call that explicitly refreshes the UI.
Some have suggested "DoEvents" as a workaround. This can work, but it is super dangerous. For two reasons. First, suppose the user clicks a button twice. During the processing of the first click, you do a DoEvents, and so you then recurse and hey, now you have suspended the processing of the first button click so that you can process the second button click... and that can't be good.
Second, suppose you're processing an event, and you do a DoEvents, which causes you to start processing another event, and then while you're doing that, you do a DoEvents, and that causes you to start processing a third event... and this keeps going forever. When do you finish processing the first event? Potentially never. Remember "DoEvents" basically means "concentrate on what just happened at the expense of what you were already working on".
While I think Jason's answer to use another thread is the way to go, there is another "evil" option.
Statuslabel.Text = "Working...";
Application.DoEvents();
LongMethod();
Statuslabel.Text = "Done";

Busy waiting in C#

How do you implement busy waiting in a not total inefficient way? I am facing the issue that I can load the data of my model only in a pull manner, which means I have to invoke getXYZ() methods in a continuous way.
This has to happen not fast enough for user interaction, but fast enought, that when a state in the GUI is changed, the model can be noticed and the new state is received by the getXYZ() methods.
My approach simply be:
while (c.hasChanged()) {
Thread.sleep(500);
}
updateData();
Are there better mechanisms?
Your problem seems to be solvable with Threading.
In WPF you can do:
Thread t = new Thread((ThreadStart)delegate() {
while (true) {
Thread.sleep(500);
if (c.hasChanged())
Dispatcher.Invoke((Action)delegate() {updateData();});
}
}).Start();
In WinForms
Thread t = new Thread((ThreadStart)delegate() {
while (true) {
Thread.sleep(500);
// this must derive from Control
if (c.hasChanged())
this.Invoke((Action)delegate() {updateData();});
}
}).Start();
There may be missing parameters to Invoke (which is needed to execute the code on the calling UI thread) but I'm writing this from my brain so no intellisense at disposal :D
In .NET 4 you can use TaskFactory.StartNew instead of spawning a thread by yourself.
In .Net <= 4, you could use the TreadPool for the thread.
However I recall you need this to be run at once because you expect it to be there checking as soon as possible and the thread pool won't assure you that (it could be already full, but not very likely:-).
Just don't do silly things like spawning more of them in a loop!
And inside the thread you should put a check like
while (!Closing)
so that the thread can finish when you need it without having to resort to bad things like t.Abort();
An when exiting put the Closing to true and do a t.Join() to close the checker thread.
EDIT:
I forgot to say that the Closing should be a bool property or a VOLATILE boolean, not a simple boolean, because you won't be ensured that the thread could ever finish (well it would in case you are closing the application, but it is good practice to make them finish by your will). the volatile keyword is intended to prevent the (pseudo)compiler from applying any optimizations on the code that assume values of variables cannot change
It's not clear from your post exactly what you are trying to do, but it sounds like you should put your model/service calls on a separate thread (via Background worker or async delegate) and use a callback from the model/service call to notify the UI when it's done. Your UI thread can then do busy things, like show a progress bar, but not become unresponsive.
If you are polling from a GUI, use a (WinForms) Timer.
If this is some kind of background process, your Sleep() may be the lesser evil.
Explicit busy waiting is evil and must be avoided whenever possible.
If you cannot avoid it, then build your application using the Observer design pattern and register the interested objects to an object which performs the polling, backed by a thread.
That way you have a clean design, confining the ugly stuff in just one place.

How to start a thread to keep GUI refreshed?

I have window with button which triggers lengthy processing. I put processing in a separate thread, but -- to my surprise -- it makes GUI frozen anyway. No control is refreshed, I cannot even move the window.
So the question is how to start the thread, so it won't interfere with GUI, i.e. so the GUI would always be up to date (while processing I change the data, and GUI displays some pieces of it)?
That is how I start thread currectly:
var thread = new Thread(doLearn);
thread.IsBackground = true;
thread.Start();
Edit 1
Jon:
I don't use any locks at all
No Join calling
The UI thread is left alone -- it simply sits there
The processing is a big loop with math operations, not even allocating memory, on UI side I have controls with binding (WPF) to data, like the number of current iteration of the main loop. It should be refreshed each time the main loop "ticks". The counter of the loop is a property which triggers OnPropertyChanged with each change (classic WPF binding).
Edit 2 -- Almost there!
Ok, so Jon hit the nail at the head (who is surprises? ;-D) -- thank you! The problem comes from changing the Counter. When I used instead the Counter, local counter the GUI was refreshed -- I mean I could move windows, but... I couldn't see display of the Counter.
What I have here -- a WPF GUI, with such data-binding
<TextBlock Text="{Binding Path=Counter"/>
and I have Counter property of course which on each change sends event PropertyChanged. One of the listeners is for sure GUI.
So, Jon answer is valid "the answer", but from good design POV not exactly, because if GUI part has to pull up the info about Counter and update the display every (let's say) 3 seconds, why would anyone use data binding? For me such approach invalidates data binding idea.
I could, theoretically, pass to the processing thread the GUI dispatcher, and do all the sending in GUI thread, and it could work (I didn't try it) but it would mean tight coupling of non-GUI part and GUI part.
So far, I have no idea how to do it "right" way. The best guess so far is to create TimerDispatcher but not at GUI side but inside the processing library, and update Counter value immediately but do all the sending from time to time (I didn't try it yet though).
Small remark: I have more properties binded actually, like IsRunning, which is changed at the beginning and at the end of processing. And those changes DO affect the display correctly -- but the Counter change triggers around 3000 notifications in 3-4 seconds. So it looks like jamming problem. I did another test -- I killed the data binding partially, so notifications were sent, but GUI was not "receiving" them -- but was listening to them. In such case the GUI was also frozen.
So, I am still listening to all advices -- thank you advance for sharing.
Edit 3
The saga continues here:
How to do the processing and keep GUI refreshed using databinding?
It should be fine as it is. Things which may be freezing your UI:
Are you locking within the UI thread, and locking on the same lock in your other thread?
Are you calling Join on the thread from your UI thread?
Are you doing some other heavy work in the UI thread?
If you could come up with a short but complete program which shows the problem, I'm sure we could help to fix it... but it certainly should be okay.
EDIT: Okay, now you've added this:
The counter of the loop is a property which triggers OnPropertyChanged with each change (classic WPF binding).
So you're updating the property from the non-UI thread? I would expect that to cause problems, because it will trigger UI changes from the wrong thread.
I suggest you take an approach such as:
Periodically update the counter via Dispatcher.BeginInvoke
Have the "UI counter" and the "worker counter" - and copy the value from the "worker counter" to the "UI counter" in the UI thread via a DispatcherTimer, essentially polling it.
There are numerous methods to run functions off the UI thread, but the easiest and generally most suitable is to look at the BackgroundWorker component. Many decent tutorials can be found. For example, here.
I put processing in a separate
thread, but -- to my surprise -- it
makes GUI frozen anyway.
I really hate to tell you, but then you did NOT put it into a separate thread. That simlpe.
There was a poster here that had a similar issue some time ago and through a mistake in his invoking code he basically had all processing before the thread started, with the thread jsut returning the result.
I faced the same situation, and solved it by two ways...
Use the thread in other class and invoke it in ur main application by creating Thread, either in its constructor OR in any method.
if u want do the it in same class, then create a Thread that call your function, and that function should invoke the Delegate.
See the examples:
public partial class Form1 : Form
{
private delegate void TickerDelegate();
TickerDelegate tickerDelegate1;
public Form1()
{
InitializeComponent();
}
//first solution
// This button event call other class having Thread
private void button1_Click(object sender, EventArgs e)
{
f = new FormFileUpdate("Auto File Updater", this);
f.Visible = true;
this.Visible = false;
}
// Second Solution
private void BtnWatch_Click(object sender, EventArgs e)
{
tickerDelegate1 = new TickerDelegate(SetLeftTicker);
Thread th = new Thread(new ThreadStart(DigitalTimer));
th.IsBackground = true;
th.Start();
}
private void SetLeftTicker()
{
label2.Text=DateTime.Now.ToLongTimeString();
}
public void DigitalTimer()
{
while (true)
{
label2.BeginInvoke(tickerDelegate1, new object[] {});
Thread.Sleep(1000);
}
}
}

Categories