So I have a thread in my application, which purpose is to listen to messages from the server and act according to what it recieves.
I ran into a problem when I wanted to fire off a message from the server, that when the client app recieves it, the client app would open up a new form. However this new form just freezes instantly.
I think what's happening is that the new form is loaded up on the same thread as the thread listening to the server, which of course is busy listening on the stream, in turn blocking the thread.
Normally, for my other functions in the clients listening thread, I'd use invokes to update the UI of the main form, so I guess what I'm asking for is if here's a way to invoke a new form on the main form.
I assume this is Windows Forms and not WPF? From your background thread, you should not attempt to create any form, control, etc or manipulate them. This will only work from the main thread which has a message loop running and can process Windows messages.
So to get your code to execute on the main thread instead of the background thread, you can use the Control.BeginInvoke method like so:
private static Form MainForm; // set this to your main form
private void SomethingOnBackgroundThread() {
string someData = "some data";
MainForm.BeginInvoke((Action)delegate {
var form = new MyForm();
form.Text = someData;
form.Show();
});
}
The main thing to keep in mind is that if the background thread doesn't need any response from the main thread, you should use BeginInvoke, not Invoke. Otherwise you could get into a deadlock if the main thread is busy waiting on the background thread.
You basically gave the answer yourself - just execute the code to create the form on the GUI thread, using Invoke.
Related
at the moment I got this
UPDATED: Thanks for all the answers.
private void Form1_Load(object sender, EventArgs e)
{
//hide() doesnt help
Thread init = new Thread(InitApplication);
init.IsBackground = true;
init.Start();
}
InitApplication takes at least 5+ seconds to complete and write in all the settings. I want my splashScreen to stay up until then.
ADDED:
private readonly SplashScreen _splash;
public Form1(SplashScreen splashy)
{
_splash = splashy;
InitializeComponent();
}
and I got
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SplashScreen splashy = new SplashScreen();
splashy.Show();
Application.DoEvents();
Application.Run(new Form1(splashy));
}
It is doing what its suppose to do, However, Now I see form1 on top of the splashform. Where can I add the hide and show method so it only the splash screen is shown and form1 popups when its fully loaded.
Try loading the splash screen from the UI thread, then use a background worker to execute InitApplication(). The background worker can communicate progress to the UI thread.
BackgroundWorker Class on MSDN
The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.
You can use Async Await, Background worker or Thread for initializing your app etc. These are written in the sequence of easy to use and the general pattern being followed.
Use a normal windows form and there use progress bar, gif image etc. what you like most there. On the form load or form shown event start the background task and when it finishes, close the normal form and load your main application form.
If your InitApplication has any call that deals with GUI, you will have to change that call and Invoke the desired action on GUI thread.
I am new to multi-threading. I am doing a project using wpf.
Brief introduction to my project:
One mainwindow
One method in mainwindow creates another thread that creates another window, which is called window 2.
Whenever window 2 is visible, mainwindow is suspended(so i used join() method to suspend the main thread)
The problem is whenever I closed the window 2, the new thread doesn't terminate. so the main thread is forever suspended. So how to solve this problem.
The following code is where i create a new thread for window 2 in MainWindow Class:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Thread addThread = new Thread(CreateCourseWindow);
addThread.SetApartmentState(ApartmentState.STA);
addThread.Start();
Thread.Sleep(TimeSpan.FromSeconds(1));
addThread.Join();
if (addcourse.Saved) CreateCourseButton(myCourses.Count(), myCourses.Last());
}
The following code is the entry function for the new thread
private void CreateCourseWindow()
{
addcourse = new AddCourse();
addcourse.Activate();
addcourse.Show();
addcourse.Topmost = true;
System.Windows.Threading.Dispatcher.Run();
}
The following code is where i want to terminate the thread
private void Button_Click_2(object sender, RoutedEventArgs e)
{
this.Close();
}
AddCourse is the window 2 class.
First off, don't create multiple UI threads. It creates a real mess that's very hard to deal with. Only ever have on UI thread in your application unless you're sure that you need more, and that you really know what you're doing.
As for this specific case, you don't need to worry about asynchrony, multiple threads, or any of it:
ChildWindow child = new ChildWindow();
this.Hide();
child.ShowDialog();
this.Show();
By using ShowDialog instead of Show you remove all the pesky asynchrony issues.
If you want the parent window visible but not enabled you can remove the show/hide but leave the ShowDialog, which will ensure the parent is disabled.
It is not advised to suspend a window by hanging the thread. What you get is a complete non-responsive window, that doesn't handle any Windows event at all. For example, it will not react to move events, or set cursor events, or other things that you would expect even a disabled window to have. Furthermore, if there are any COM STA objects on this thread they will hang (and sometimes there can be such object even if you didn't explicitly create them).
How are you opening the window from the second thread? It sounds like this thread is running a loop which doesn't terminate when the window is closed. If you post some code it can help.
I have a main form that contains an edit control that occupies the entire form. There is another worker thread that constantly writes log messages to this edit control. Now I want to show a dialog box with just a cancel button while the main UI's edit control is displaying stuff. The problem is that the cancel dialog is non-responsive while the updates are happening behind it and I cannot click on the cancel button. Any idea on how to resolve it. I was thinking of creating another UI thread and show the cancel button from it. Any other alternatives?
EDIT#1
I should clarify that I already use a worker thread to do the work.
DisplayLogs() is in a seperate thread.
DisplayLogs() is called from other threads.
LogMessage is the delegate that points to the method UpdateMessage in main UI.
The control used is a TextBox. I have tried other controls like listview,
richtextboxsand, etc. still the same result.
Worker Thread
void DisplayLogs()
{
lock (this)
{
while (logQueue.Count > 0)
{
string logMessagemessage = logQueue.Dequeue();
LogMessage(string.Concat(logMessagemessage, Environment.NewLine));
}
}
}
Main UI
public void UpdateMessage( string message)
{
if (!txtLog.IsHandleCreated)
{
return;
}
if (txtLog.InvokeRequired)
txtLog.BeginInvoke( new UpdateLogDelegate( UpdateLog), message);
else
txtLog.AppendText(message);
}
The main solution is to offload the expensive code onto a background worker and leave your UI thread responsive for UI actions. Your form can then simply show a modal dialog or something.
MSDN - How to use a Background Worker
In this situation it's necessary to move the majority of the work to a new thread, and clear up the UI thread for cancel messages etc.
You are going about this backwards. The main thread should, in theory, always be available to accept user input. Anything that may block for extended periods of time (heavy computation, database access, network access) should be done in a background thread. The idea is to have the edit control's data being computed and populated by a background thread (BackgroundWorker objects work nicely here) so that the main thread is always available if the user clicks on the cancel button.
Your problem is that the your UI thread is ALWAYS busy. I am saying this assuming that the number of items in logQueue is quite large. The while loop doesn't quit till the queue is empty. So it keeps hitting the UI thread with request for updates.
Also the if (txtLog.InvokeRequired) is kind of pointless because you are always calling the method from a worker thread.
So, since a .net WinForm application has only a single UI, which in your case is too busy to process other notifications, the new window appears stuck (because the paint messages are stuck in the message queue and cannot be processed as it is already flooded with the text box update messages)
You could stick an Application.DoEvents inside your loop which will give the message loop some time to process the pending notifications. However this is kind of a hack, in my opinion, as the UI behavior is sometimes not predictable. It may lead to things like stuttering while moving a dialog, delayed responses to click events etc.
Another point, MessageBox.Show or a Form.ShowDialog (if this is what you are using for the cancel button) is a blocking call. The thread on which you show it WILL hang till you dismiss the dialog. Try Form.Show and set the parent property to the main form.
Another alternative is to add a timer and process only X notifications per Y seconds. This will give the UI thread some breathing room for performing other activities.
Is there any way to load window inside the background worker thread without using showdialog()? the background worker only terminate only after getting some input from the window. Here the issue is window shown but the button and other controls are not rendered even we don't have control over any of the window.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// acquire form
Acquire aq = new Acquire(Handle);
aq.Show();
do
{
// waiting for image
} while (!aq.isImageReady);
// doing Image operation
}
You can show the dialog before you start the background worker, and declare a volatile var that you can change/check in the background worker and keep it running until it will have your desired value, that will be achieved once the dialog is closed.
The problem might be because you're using the background thread to show the window instead of the main UI thread of the process. Winform controls either throw exceptions or behave incorrectly if they are not used on the proper thread. In this case, the problem might be that your main window is running on the main UI thread while this additional dialog window is being created and shown by a different thread.
Try raising an event from the background thread to let the UI know that it requires input from the user. The UI can then handle displaying the dialog and responding to the user's input by passing the data back to the background thread.
In order to prevent the background thread from proceeding any further, create a System.Threading.AutoResetEvent object (a WaitHandle) and call the WaitOne method on that object immediately after raising the event to notify the UI to show the dialog. When the UI responds to the user input by passing the data back to the background thread, that code can call the Set method on the AutoResetEvent object, allowing the background thread to proceed.
Ok, so I found something weird over the weekend. I have a WPF app that spawns off some threads to perform background work. Those background threads then Post work items to my Synchronization Context. This is all working fine except for one case. When my threads finish sometimes they will post an action onto the dispatcher that will open up a Popup window. What ends up happening is that if 2 threads both post an action on the Dispatcher it starts processing one, then if I open up a Popup window with Window.ShowDialog(); the current execution path pauses waiting for feedback from the dialog box as it should. But the problem arises that when the dialog box opens the Dispatcher then goes and starts immediately starts running the second action that was posted. This results in two code paths being executed. The first one with a message box being held open, while the second one is running wild because my application state is unknown because the first action never completed.
I've posted some example code to demonstrate the behavior I'm talking about. What should happen is that if I post 2 actions and the 1st one opens up a dialog box the second action shouldn't run until after the 1st action has been completed.
public partial class Window1 : Window {
private SynchronizationContext syncContext;
public Window1() {
InitializeComponent();
syncContext = SynchronizationContext.Current;
}
private void Button_ClickWithout(object sender, RoutedEventArgs e) {
// Post an action on the thread pool with the syncContext
ThreadPool.QueueUserWorkItem(BackgroundCallback, syncContext);
}
private void BackgroundCallback(object data) {
var currentContext = data as SynchronizationContext;
System.Console.WriteLine("{1}: Thread {0} started", Thread.CurrentThread.ManagedThreadId, currentContext);
// Simulate work being done
Thread.Sleep(3000);
currentContext.Post(UICallback, currentContext);
System.Console.WriteLine("{1}: Thread {0} finished", Thread.CurrentThread.ManagedThreadId, currentContext);
}
private void UICallback(object data) {
System.Console.WriteLine("{1}: UI Callback started on thread {0}", Thread.CurrentThread.ManagedThreadId, data);
var popup = new Popup();
var result = popup.ShowDialog();
System.Console.WriteLine("{1}: UI Callback finished on thread {0}", Thread.CurrentThread.ManagedThreadId, data);
}
}
The XAML is just a Window with a button that calls Button_ClickWithout OnClick. If you push the button twice and wait 3 seconds, you will see you get 2 dialogs popping up one over the other, where the expected behavior would be the first one pops up, then once it's closed the second one will pop up.
So my question is: Is this a bug ? or how do I mitigate this so I can have only one action be processed at a time when the first action halts execution with a Window.ShowDialog() ?
Thanks,
Raul
As I'm awaiting an answer on my question (Advice on using the Dispatcher Priority and Binding) I thought that would pay-it-forward™.
What you are experiencing is Nested Pumping on the Dispatcher. I recommend reading the MSDN article on the WPF Threading Model, especially the section titled 'Technical Details and Stumbling Points' that is two-thirds down the page. The sub-section describing the Nested Pumping is copied below for convenience.
Nested Pumping
Sometimes it is not feasible to completely lock up the UI thread.
Let’s consider the Show method of the MessageBox class. Show doesn’t
return until the user clicks the OK button. It does, however, create a
window that must have a message loop in order to be interactive. While
we are waiting for the user to click OK, the original application
window does not respond to user input. It does, however, continue to
process paint messages. The original window redraws itself when
covered and revealed.
Some thread must be in charge of the message box window. WPF could
create a new thread just for the message box window, but this thread
would be unable to paint the disabled elements in the original window
(remember the earlier discussion of mutual exclusion). Instead, WPF
uses a nested message processing system. The Dispatcher class includes
a special method called PushFrame, which stores an application’s
current execution point then begins a new message loop. When the
nested message loop finishes, execution resumes after the original
PushFrame call.
In this case, PushFrame maintains the program context at the call to
MessageBox.Show, and it starts a new message loop to repaint the
background window and handle input to the message box window. When the
user clicks OK and clears the pop-up window, the nested loop exits and
control resumes after the call to Show.
A modal dialog box does not prevent the owner window from processing messages, otherwise you'd see it fail to redraw as the modal dialog was moved over its surface (just as an example).
In order to achieve what you want, you have to implement your own queue on the UI thread, possibly with some synchronization to "wake it up" when the first work item arrives.
EDIT:
Also if you examine the call stack of the UI thread while the 2nd modal dialog box is up, you might find out that it has the first ShowDialog call above it in the stack.
EDIT #2:
There might be an easier way of doing this, without implementing your own queue. If instead of the SynchronizationContext, you would use the Dispatcher object, you would be able to call BeginInvoke on it with a priority of DispatcherPriority.Normal, and it will get queued properly (check).