UI Thread is Blocked when showing Splash Screen [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# Splash Screen Problem
I am new to c# , i am working on splash screen which runs when the software starts.. I have a function in splash Screen class which checks the database. I am using thread to call the function
sc = new splashScreen();
checkDLLThread = new Thread(new ThreadStart(sc.checkDLLS).BeginInvoke);
checkDLLThread.Start();
while (checkDLLThread.IsAlive)
{
Thread.Sleep(200);
}
Problem is UI is blocked until the thread is Alive. And in final it give me database connection status message.
Here is my code. I have used checkDLLThread.join() but it also doesnt work.

A splashscreen is simply an image to 'amuse' the user while your app is loading. Use the app_load method to execute code on startup:
Like so: (in app.xaml and app.xaml.cs)
<Application /some references to stuff/ Startup="Application_Startup" >
private void Application_Startup(object sender, StartupEventArgs e)
{
// your startupcode
}
Also, I think the BackGroundworker class is better for things like this, if you don't want to bother the UI.

Unblocking the UI thread requires returning from your event handler. There is no alternative to doing that. Here is some pseudo-code:
OnStartup:
Start new Thread
Disable UI
Show Splash Sceen
Return!
Thread:
Check Database
if (not ok)
Show Message box
Exit Application
else
Enable UI
Remove Splash Screen
The trick is to let the thread show the message and so one once it is done. Don't wait for the thread, let the thread do it itself.
Your thread probably needs to use the Invoke function to access the UI. You might wan't to read about that a bit because there is no way around it if you want to do asynchronous work on a background thread.

The following code launches a "splash screen" on a separate thread whilst your application (in my example below it is called MainForm()) loads or initialises. Firstly in your "main()" method (in your program.cs file unless you have renamed it) you should show your splash screen. This will be a WinForm or WPF form that you wish to show the user at start up. This is launch from main() as follows:
[STAThread]
static void Main()
{
// Splash screen, which is terminated in MainForm.
SplashForm.ShowSplash();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Run UserCost.
Application.Run(new MainForm());
}
In your SplashScreen code you need something like the following:
public partial class SplashForm : Form
{
// Thredding.
private static Thread _splashThread;
private static SplashForm _splashForm;
public SplashForm()
{
InitializeComponent();
}
// Show the Splash Screen (Loading...)
public static void ShowSplash()
{
if (_splashThread == null)
{
// show the form in a new thread
_splashThread = new Thread(new ThreadStart(DoShowSplash));
_splashThread.IsBackground = true;
_splashThread.Start();
}
}
// Called by the thread
private static void DoShowSplash()
{
if (_splashForm == null)
_splashForm = new SplashForm();
// create a new message pump on this thread (started from ShowSplash)
Application.Run(_splashForm);
}
// Close the splash (Loading...) screen
public static void CloseSplash()
{
// Need to call on the thread that launched this splash
if (_splashForm.InvokeRequired)
_splashForm.Invoke(new MethodInvoker(CloseSplash));
else
Application.ExitThread();
}
}
This launches the splash form on a separate background thread allowing you to proceed with the rendering of your main application simultaneously. To display messages about loading you will have to pull information from the main UI thread, or work in purely aesthetic nature. To finish off and close the splash screen down when your application has been initialised you place the following inside the default constructor (you could overload the constructor if you wanted to):
public MainForm()
{
// ready to go, now initialise main and close the splashForm.
InitializeComponent();
SplashForm.CloseSplash();
}
The code above should be relatively easy to follow.
I hope this helps.

Your approach is good, but you should run both simultaneously. A good use of static fields can do the job easily. Instead of:
while (checkDLLThread.IsAlive)
{
Thread.Sleep(200);
}
You should:
Show the Splash Form
Set the form to be hidden on start, i.e. set Opacity to 0
Check steadily for a variable in the SplashForm when your form is completely initialized
Set Opacity back to 1 when the thread is complete. i.e. variable changes
i.e.:
public Form1(){
InitializeComponent();
Opacity = 0;
while(sc.IsComplete){}
Opacity = 1;
}
And inside your SplashForm, you should have something like:
internal static bool IsComplete;
internal static void CheckDLLS()
{
//after doing some stuff
IsComplete = true;
}

Related

Not updating GUI in time

I have a class that updates a GUI element
public class UpdateLabelClass
{
static MainGUI theForm = (MainGUI)Application.OpenForms[0];
Label lblCurProgress = theForm.curProgress;
public ProgressBarUpdate()
{
}
public void UpdateLabel(String newLabel)
{
lblCurProgress.Text = newLabel;
}
}
And in other classes, I make an instance of the class and call the UpdateLabel(someString);
Now the problem is, it skips the operation of updating the label, so I thought "Maybe it isn't even reaching the code", so I put a MessageBox.Show() right after it, and it updated the label.
What are possible causes to skip the label update, but perform it when I put a message bow right after? Is the program going to fast?
Most likely you are improperly running a long operation in the main UI thread which prevents the label from updating. You could "fix" this by calling DoEvents():
public void UpdateLabel(String newLabel)
{
lblCurProgress.Text = newLabel;
Application.DoEvents();
}
But this is just a band-aid on top of a bad design. You should properly move that code to a background thread and use a delegate/Invoke() to update the label.
Edit: (answering followup question)
By default, your application runs in a single thread. This includes the code that you add to control events, as well as the code that you can't see that is running behind the scenes to make your application respond in the way you'd expect. Things like user interaction (mouse clicks, keyboard presses, etc.) and painting messages (when controls are changed, your window is obscured) are placed into a queue. Those pending messages in the queue only get processed once your code has stopped running. If you have a lengthy chunk of code running, like a long loop, then those messages just sit in the queue waiting to be processed. Thus the update to the label doesn't occur until after your loop is done. What DoEvents() does is tells the application to process those pending messages in the queue, right now, and then return to the code that was currently executing. This allows the label to update in real-time like you expect it to.
When you encounter situations that are "fixed" by DoEvents(), it simply means that you are attempting to run too much code in the main UI thread. The main UI thread is supposed to be focused on responding to user interaction and keeping the display updated. Code in control event handlers should be short and sweet, so that the main UI thread can get back to doing its main job.
The proper fix is to move that lengthy code to a different thread, thus allowing the main UI thread to respond and keep itself updated. For many scenarios, the easiest approach is to place a BackgroundWorker() control on your form and wire up the DoWork(), ProgressChanged() and RunWorkerCompleted() events. *You have to set the WorkerReportsProgress() property to true, however, to handle the ProgressChanged() event. The latter two events are already marshaled to the main UI thread for you so you don't need to worry about cross-thread exceptions. From the DoWork() handler, you call ReportProgress() and pass out a progress percentage value and an optional other object (it could be anything). Those values can be retrieved in the ProgressChanged() event and used to update the GUI. The RunWorkerCompleted() event fires when all the work in the DoWork() handler has been finished.
In your case, you've got a separate class that is doing the work. You can mirror what the BackgroundWorker does by manually creating your own thread in that class to do the work. When you want to update progress, make your class raise a Custom Event that the main form subscribes to. When that event is received, however, it will be running in the context of the separate thread. It is necessary, then, to "marshal" the call across the thread boundaries so that the code is running in the main UI thread before you update the controls. This is accomplished by using delegates ("pointers" to methods) and the Invoke() method. *There are other methods to accomplish this task as well, such as a SynchronizationContext.
See here for some examples of these approaches.
Finally, here is a super simple example of a class that raises custom events from a separate thread:
public partial class Form1 : Form
{
private Clock Clk;
public Form1()
{
InitializeComponent();
Clk = new Clock();
Clk.CurrentTime += new Clock.TimeHack(Clk_CurrentTime);
}
private void Clk_CurrentTime(string hack)
{
if (label1.InvokeRequired)
{
Clock.TimeHack t = new Clock.TimeHack(Clk_CurrentTime);
label1.Invoke(t, new object[] { hack });
}
else
{
label1.Text = hack;
}
}
}
public class Clock
{
public delegate void TimeHack(string hack);
public event TimeHack CurrentTime;
private Thread t;
private bool stopThread = false;
public Clock()
{
t = new Thread(new ThreadStart(ThreadLoop));
t.IsBackground = true; // allow it to be shutdown automatically when the application exits
t.Start();
}
private void ThreadLoop()
{
while (!stopThread)
{
if (CurrentTime != null)
{
CurrentTime(DateTime.Now.ToString());
}
System.Threading.Thread.Sleep(1000);
}
}
public void Stop()
{
stopThread = true;
}
}
public void UpdateLabel(String newLabel)
{
lblCurProgress.Text = newLabel;
lblCurProgress.Refresh();
}

how to create thread work with gui

I'm novice in program with c#. I want to create thread that move label in the main UI without stuck the UI until the movement done
I built something but it didnt work
tell me what is my problem
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(Movelb);
t.IsBackground = true;
t.Start();enter code here
}
private void DOsomeThing()
{
label2.Visible = true;
label2.Location = new Point(0, 205);
for (int i = 0; i < 533; i++)
{
label2.Location = new Point(i, 205);
Thread.Sleep(10);
}
label1.Text="false";
}
private void Movelb()
{
if (this.InvokeRequired)
{
threadDel d = new threadDel(DOsomeThing);
this.BeginInvoke(d);
}
else
DOsomeThing();
}
Do not use threads to paint to forms or modify/update form contents. The recommended paradigm in Windows programming is One Thread Per Form or Window. If you want to create forms that run from separate threads, then you must
create the new thread first
create the Form on the new thread
In this way, the new thread will serve as the new Form's message handler. But even then, you should still do all manipulation of the Form within that thread (and if the form wants to modify contents in another form running on a different thread, then some additional thread-safe communication trickery may be required).
To animate window contents, you should use System.Windows.Forms.Timer instead, which executes on the Form's thread in lock-step with its other messages. You'll need to re-implement your animation as a state machine rather than a for() loop construct, though. That means the variables for Label position will need to be embedded into the Form class, so that updates can be preserved across Timer message invocations.
You need to understand the event model first. In event-driven environments like Windows or Android or Linux etc... the "automatic " tasks such as animations of coordinates or other properties are usually done using Timers that keep re-sending events back to the handler that advances the animation/process. In your particular example - if you need to move label, use Widows.Forms.Timer. It is not appropriate to block UI thread that processes events with lengthy tasks as UI thread will stall and your app will freeze or become jerky. NOW, on the other hand there are many cases when adding extra threads DOES help a lot, when? Not in your case, because you only change the coordinate of the label that is nothing in terms of CPU in comparison to repaint, so your solution with extra thread is LESS efficient and much more complex than using timer. An extra thread is beneficial only when the logical work it performs on animation model is comparable or out-weights the paint work- imagine a game where 200 bugs need to be animated on screen according to many logical rules, in this case bug painting may be done in UI thread, but bug property changes/animations may be done in another thread if those computations are intense.
How Events work?
An OS has an infinite loop inside that gets interrupted by keyboard, mouse and other events but the loop spins indefinitely until you shut down Windows (or Android or XWidnws...). At the end of the loop the OS looks at "raw" mouse/key events and dispatches them into appropriate application queue. It knows it by inspecting every app windows list, who is on top and thus it knows what window/app was under such and such X,Y mouse coordinate. When event gets dispatched to your app your job is to handle it very fast and look for another event in your queue (queues are bound to UI Threads/Windows).
How Timers Work?
A timer is a special kind of event that OS can keep sending to you periodically from its internal "infinite loop". OS keeps track of what apps requested to be notified and how often - when time comes, it adds a WM_TIMER(on MS Windows) into your windows queue. This way you don't block anything, but get a method in your code that gets called every X milliseconds. When you use .NET Timer class - it is just a wrapper around CreateTimer() KillTimer() (I dont recall exact func names) in Windows User APIs. .NET Timer also knows how to swallow the WM_TIMER and call a C# event/delegate for you.
I hope this helps!
Your code does nothing useful. It just starts a new background thread, which, in turn, invokes a delegate, being executed at the same UI thread, which had started... the background thread.
In other words, you can't move the label in worker thread, because moving the label brings to repainting, which can't be done from background thread.
I also had an idea of doing some work in a thread - and while this hard job
was carried out... the main-gui-form should be modified, so the user will
spot a progress.
Did some lookup and went into "delegates", "eventhandlers", and "very advanced pieces of code".
It took me some time to fix, and I came up with this very simple example. Have a look.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ProcessingUI
// You will find a form with "button1": will do some work in a seperate thread, and
// therefore you are allowed to do action in main-gui-form while this work is done,
// due to async. operation.
// While work is done in seperate thread - the main-gui-form will have a label modified...
// having the steps: 1,2,3,0.
// Also found... "button2": will do some work in same thread as gui, and
// therefore you are not allowed to do action in main-gui-form while this work is done,
// due to sync. operation (only one thread is established).
// While work is done in one-and-only-thread - the main-gui-form will have a label modified...
// having the steps: 1,2,3,0.
{
public delegate void UpdateTextDelegate();
public partial class Form1 : Form
{
public delegate void SetStatusText(string statusText);
public SetStatusText mySetStatusTextDelegate;
public Form1()
{
InitializeComponent();
mySetStatusTextDelegate = new SetStatusText(SetStatusTextMethod);
}
private void button1_Click(object sender, EventArgs e) // do work from new thread.
{
Worker w = new Worker(this);
Thread thread1 = new Thread(new ThreadStart(w.DoWork));
thread1.Start();
}
private void button2_Click(object sender, EventArgs e) // do work from local class - form is locked during 1-3 steps.
{
SetStatusTextMethod("1");
Thread.Sleep(3000);
SetStatusTextMethod("2");
Thread.Sleep(3000);
SetStatusTextMethod("3");
Thread.Sleep(3000);
SetStatusTextMethod("0");
}
public void SetStatusTextMethod(string statusText)
{
label1.Text = statusText;
label1.Refresh();
}
}
public class Worker
{
Form1 guiForm; // holds form where "control-to-be-changes" is found.
public Worker(Form1 _guiForm)
{
guiForm = _guiForm;
}
public void DoWork() // while steps are being done - form can easily be moved around... is not locked!
{
// put "1/3" on form.
guiForm.Invoke(guiForm.mySetStatusTextDelegate, "1");
Thread.Sleep(3000);
// put "2/3" on form.
guiForm.Invoke(guiForm.mySetStatusTextDelegate, "2");
Thread.Sleep(3000);
// put "3/3" on form.
guiForm.Invoke(guiForm.mySetStatusTextDelegate, "3");
Thread.Sleep(3000);
guiForm.Invoke(guiForm.mySetStatusTextDelegate, "0");
}
}
}

Threading issue - Window not updating/responding [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
WPF and cross thread operations
I am having trouble with a window in my wpf application displaying, but not updating the view. When placing the cursor over the opened window the loading icon is shown and the window is unresponsive. I am thinking this is likely due to some threading issue I don't have enough experience in seeing.
Here is the setup:
My main program runs on startup and creates and instance of a MainWindow window which implements a custom interface (IPlayer). The main program then runs a process which interracts with IPlayer to accomplish some task, the idea being that the main program requests actions from the MainWindow, which prompts the user for some sort of input and displays the results.
I'll simplify the code for clarity. Assume this program simply runs a sort of chatter bot game.
class MainProgram
{
[STAThread]
static void main(string[] args)
{
MainWindow wdw = new MainWindw();
Game g = new Game(wdw);
wdw.Show();
g.RunGame();
}
}
class Game
{
public IPlayer p;
Game(IPlayer) { this.p = p; }
public RunGame()
{
string r = GetResponse("How was your day?");
...
}
}
public partial class Human_Player : Window, IPlayer
{
public string GetResponse(string Question)
{
ShowQuestion(Question);
string r = GetResponse();
DisplayResponse(r);
return r;
}
...
}
I gave running RunGame() in a separate thread a shot like this:
Thread thread = new Thread(new ThreadStart(game.RunGame));
thread.Start();
but got an InvalidOperationException in response stating "The calling thread cannot access this object because a different thread owns it."
Any help here would be appreciated since I'm pretty new to this stuff. Thanks ahead of time!
EDIT:
Just to clarify, I'm not creating any new threads at the moment. Thus I don't think I'm doing any multi-threading. I'm attempting to run game.RunGame() on the main thread after opening the window. The runGame method consists of a large loop which calls a method on the Human_Player window that changes the UI.
As far as I know there are only two threads:
- Main Thread - MainProgram and Game run here. I think the windows runs here as well but I could be wrong... please clarify
- Rendering Thread - the UI is rendered here.
Argh, this question is asked soooo many times... You cannot update a GUI control from a different thread than the Dispatcher thread associated to the control. You will need to run your update code using Dispatcher.BeginInvoke to update the GUI from the correct thread.
If you are not running the code from a different thread then it's possible that your method is taking too long to execute, thus causing the GUI to hang because the event thread is blocked from accepting user input.
It sounds like your game code is running in a loop and stealing all your UI's processing time. It doesn't sound like you are releasing control to your dispatcher.
Your game code shouldn't loop, it should run an iteration once and then return control to the dispatcher. You need to create a timer control that will call your game code at regular intervals instead.

correct method of threading

I am very new to WPF. And just started learning threading.
Here is my scenario:
I've created a program with a button named START. When start button is clicked it starts to do some complex task in different thread. Just before beginning the complex task it also creates a UI elements in another STA thread (technically i don't know what i am saying).
Here is a sample code:
// button click event
private void button1_Click(object sender, RoutedEventArgs e)
{
System.Threading.Thread myThread = new System.Threading.Thread(
() => buttonUpdate("Hello "));
myThread.Start();
}
private void buttonUpdate(string text)
{
System.Threading.Thread myThread = new System.Threading.Thread(createUI);
myThread.SetApartmentState(System.Threading.ApartmentState.STA);
// set the current thread to background so that it's existant will totally
// depend upon existance of main thread.
myThread.IsBackground = true;
myThread.Start();
// Please don't read this loop it's just for my entertainment!
for (int i = 0; i < 1000; i++)
{
System.Threading.Thread.Sleep(100);
button1.updateControl(new Action(
() => button1.Content = text + i.ToString()));
if (i == 100)
break;
}
// close main window after the value of "i" reaches 100;
this.updateControl(new Action(()=>this.Close()));
}
// method to create UI in STA thread. This thread will be set to run
// as background thread.
private void createUI()
{
// Create Grids and other UI component here
}
The above code succesfully does what i want to do. But do you think it's the correct way? so far i don't have any problem here.
EDIT: OOps I forgot to mention this class:
public static class ControlException
{
public static void updateControl(this Control control, Action code)
{
if (!control.Dispatcher.CheckAccess())
control.Dispatcher.BeginInvoke(code);
else
code.Invoke();
}
}
If you are using .NET 4.0 you might want to consider using the Task class from the Task parallel library. Read into it since you say you are new to threading. It's much more flexible to use.
Also I think that this link could be very helpful to you:
http://www.albahari.com/threading/
There seems to be no good reason to use 2 threads.
You should be able to execute the createUI() on the main thread. That'll be complicated enough when it becomes time to fill those controls.
Only one thread can interact with the UI. If you are going to add a control to a page or windows then you must use the thread that created the page or window. The typical scenario is to use threading to create expensive data or object in the background and then on the callback (running on the primary thread) retrieve the result and bind appropriate data to the UI. Look at using BackgroundWorker as it takes care of a lot of the threading detail for you. http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx Why do you want to create UI objects on another thead?

Vanishing WindowsForm

I am developing a plugin for an application, that application "consumes" my code (classLibrary), and executes the Init() method inside his own Thread.
Inside the Init() I have a while(true) statement, so that my plugin can run continuously.
Yesterday, I started to make a windowsForm for configuration of my plugin (using XML), and now I want to show it, but it keeps vanishing. My code is as follows:
Doing this will show the form, but, it wont re-paint because it is launched on that same thread as the while(true) is.
MaForm settingsForm = null;
void init(){
While(true){
if(settingsForm == null){
settingsForm = new MaForm();
settingsForm.show();
}
}
}
Version that shows, but then vanishes.
MaForm settingsForm = null;
Thread worker = null;
void init(){
While(true){
if(worker == null){
worker = new Thread(new ThreadStart(formStuff));
worker.Start();
}
}
}
void formStuff()
{
if(settingsForm == null){
settingsForm = new MaForm();
settingsForm.show();
}
}
What am I doing wrong? Is there something about Threading I am missing?
What do you guys think?
The thread is starting, showing your form, then finishing up and shutting down (which closes the form).
Showing a form on a separate thread is nearly always problematic. Forms require a message pump to be running - so they typically will only work properly if they're started and run on the GUI thread.
One option would be to invoke the function to show your form onto your main thread. This will make your form load (and run) on the main thread.
Alternatively, you can start an entire message pump on the form's thread, and set the thread to STA (this is important). However, I suggest avoiding this approach if possible.
you can try this: create the form, enter the infinite loop, call DoEvents() so that your form can process windows messages:
if(settingsForm == null){
settingsForm = new MaForm();
settingsForm.show();
}
while (settingsForm != null && settingsForm.Visible)
{
System.Windows.Forms.Application.DoEvents();
}
EDIT: may be you can replace the true condition by a check on the SettingsForm visibility. When the form is closed, it's a waste to stay in an infinite loop.
A good way of dealing with threading issues in C# is to comment out using System.Threading; at the top of your classes and forms. You may have some compelling reason for showing forms with a Thread, but probably not, since Form.Show() is not a blocking call.
if you're trying to show a form from your Main() method, try using ShowDialog() instead. This call will block until the form is closed.

Categories