Thread.Start not working - c#

I am using the functions of the following class to invoke a messagebox. I am using thread.Start method to show the messagebox. The problem is it is not reaching to the respective function when thread.Start is called. Am i missing anything?
class MessageManager
{
string _message;
public MessageManager(string message)
{
_message = message;
}
public void ShowBigMessage()
{
Thread thread = new Thread(DisplayBigMessage);
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();
// thread.Join();
}
public void ShowNormalMessage()
{
Thread thread = new Thread(DisplayNormalMessage);
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();
//thread.Join();
}
private void DisplayBigMessage()
{
BigAppMessage appMessage = new BigAppMessage(_message);
appMessage.Show();
}
private void DisplayNormalMessage()
{
AppMessage appMessage = new AppMessage(_message);
appMessage.ShowDialog();
}
}
This is called inside a thread/delegate as below. I added this code into my program becuase it was raising
The calling thread must be STA, because many UI components require
this.
exception before
MessageManager message = new MessageManager("This is a test message.");
message.ShowBigMessage();
public partial class BigAppMessage : Window
{
public BigAppMessage(String message)
{
InitializeComponent();
myControl.setMessage(message); // mycontrol is just user control with a
//label on it
}
}

The Show() method requires a message loop. Fix:
private void DisplayBigMessage()
{
Application.Run(new BigAppMessage(_message));
}
There's already a message loop built into the ShowDialog() method. Using a thread to just display a window has no advantages, only problems.

In visual studio go to Debug->Exceptions and check the "thrown" box next to CLR exceptions. this will tell you where your problem is. Probably its a cross thread issue since you would ordinarily only interact with the UI on the UI thread.

Related

When an object becomes a property of syncronizationContext?

I wrote this code starting from new winform project.
public partial class Form1 : Form
{
object o = new object();
public Form1()
{
InitializeComponent();
Task t = new Task(foo);
t.Start();
Thread.Sleep(500);
Monitor.Enter(o);
}
private void foo()
{
Monitor.Enter(o);
Thread.Sleep(1000);
ActionOnUI();
Console.WriteLine("Thread End");
Monitor.Exit(o);
}
delegate void ActionOnUICrossThread();
public void ActionOnUI()
{
if (InvokeRequired)
{
this.BeginInvoke(new ActionOnUICrossThread(ActionOnUI));
}
else
{
textBox1.Text += "ab";
}
}
}
I've used thread.sleep to stop mainThread on Monitor meanwhile the task run.
With breakpoint on if(InvokeRequired) i can see that InvokeRequired is false, i expected it to be true.
If i remove Thread.Sleep(500); Monitor.Enter(o); on Form1 ctor the InvokeRequired is true, as i expected.
why is there this different behavior?
Task is not a thread. It merely represents an asynchronous operation. It is up to the task scheduler to put it on a thread or keep it on the same one.
Because you're blocking the form construction by Monitor.Enter(o); inside constructor which always loses race conditions to Monitor.Enter(o); inside foo due to 500 ms sleeping.

Setting Control properties from separate thread/class

I've searched and can't find a solution that helps me get text from a thread running in a separate class, back to a listbox on the form that created the thread.
Basically I have a class that holds a "test", it is called in it's own thread from a test window. What I want to be able to do is add text to a listbox on the main form to let the user know what is going on with a test. All the examples I can find on Invoke show how to do it within the same class.
Where I start the thread:
PermeabilityTest Run_Test = new PermeabilityTest();
public Thread WorkerThread;
private void button2_Click(object sender, EventArgs e)
{
//enable timer for test duration display
timer1.Enabled = true;
//create and start new thread.
WorkerThread = new Thread(Run_Test.RunTest);
WorkerThread.Start();
}
Here is my class that actually does the work, where I need to get text back to a listbox on a separate form from.
public class PermeabilityTest
{
//volatile alerts the compiler that it will be used across threads.
private volatile bool aborted;
public void RequestStop()
{
//handle saving data file here as well.
aborted = true;
}
public void RunTest()
{
//reference the comms class so we can communicate with the machine
PMI_Software.COMMS COM = new COMMS();
//some test stuffs here
int x = 0;
while( x < 100 && !aborted)
{
System.Diagnostics.Debug.Write("Well here it is, running it's own thread." + Environment.NewLine);
COM.Pause(1);
}
}
}
I would appreciate any one who could help me understand how to get some text back to a listbox on the same form that has the button which starts the thread.
Option 1: (Preffered) Add an event on PermeabilityTest and register on that event in your main form.
Then modify the content of your List box from within your main form.
Example:
Your main form:
PermeabilityTest Run_Test = new PermeabilityTest();
public Thread WorkerThread;
public form1()
{
// Register on the Progress event
Run_Test.Progress += Run_Test_Progress;
}
void Run_Test_Progress(string message)
{
if(listBox.InvokeRequired)
{
// Running on a different thread than the one created the control
Delegate d = new ProgressEventHandler(Run_Test_Progress);
listBox.Invoke(d, message);
}
else
{
// Running on the same thread which created the control
listBox.Items.Add(message);
}
}
private void button2_Click(object sender, EventArgs e)
{
//enable timer for test duration display
timer1.Enabled = true;
//create and start new thread.
WorkerThread = new Thread(Run_Test.RunTest);
WorkerThread.Start();
}
new Delegate:
public delegate void ProgressEventHandler(string message);
Modified PermeabilityTest class:
public class PermeabilityTest
{
//volatile alerts the compiler that it will be used across threads.
private volatile bool aborted;
public event ProgressEventHandler Progress;
public void RequestStop()
{
//handle saving data file here as well.
aborted = true;
}
public void RunTest()
{
//reference the comms class so we can communicate with the machine
PMI_Software.COMMS COM = new COMMS();
//some test stuffs here
int x = 0;
while (x < 100 && !aborted)
{
// Report on progress
if(Progress != null)
{
Progress("This message will appear in ListBox");
}
System.Diagnostics.Debug.Write("Well here it is, running it's own thread." + Environment.NewLine);
COM.Pause(1);
}
}
}
Option 2:
You could make PermeabilityTest an inner class of your main form, and by doing so, allow it to access private members of your main form.
Then you need to pass a reference of your main form to the constructor of PermeabilityTest and keep it as a member.
Option 3:
pass your list box to the constructor of PermeabilityTest
Don't forget to use Invoke on your control since you are running from a different thread.

How to update textboxes in main thread from another thread?

How you update textboxes and labels in the main thread from a new thread running a different class.
MainForm.cs (Main thread)
public partial class MainForm : Form
{
public MainForm()
{
Test t = new Test();
Thread testThread = new Thread(new ThreadStart(t.HelloWorld));
testThread.IsBackground = true;
testThread.Start();
}
private void UpdateTextBox(string text)
{
textBox1.AppendText(text + "\r\n");
}
}
public class Test
{
public void HelloWorld()
{
MainForm.UpdateTextBox("Hello World");
// How do I execute this on the main thread ???
}
}
I have looked at the examples on here but cant seem to get it right. Please could someone give some good links.
I have started again fresh so I don't mess up my code. If anyone would like to put up a working example with my example that would be great.
Also if I had to update multiple objects like textboxes and labels etc (not all at the same time) what would be the best way to go about it, having a method for each textbox or is there a way to do this with one method?
Invoke or BeginInvoke, e.g.
Invoke((MethodInvoker)delegate {
MainForm.UpdateTextBox("Hello World");
});
#tiptopjones I guess you're asking also how to get a reference to the form. You could make your HelloWorld method take an object parameter, use the ParameterizedThreadStart delegate, and then pass a reference to the form as a parameter to the Thread.Start method. But I would suggest reading about anonymous methods which makes it a lot easier and keeps everything strongly typed.
public class MainForm : Form {
public MainForm() {
Test t = new Test();
Thread testThread = new Thread((ThreadStart)delegate { t.HelloWorld(this); });
testThread.IsBackground = true;
testThread.Start();
}
public void UpdateTextBox(string text) {
Invoke((MethodInvoker)delegate {
textBox1.AppendText(text + "\r\n");
});
}
}
public class Test {
public void HelloWorld(MainForm form) {
form.UpdateTextBox("Hello World");
}
}
When you get comfortable with that you could read up on lambda expressions and do it like:
Thread testThread = new Thread(() => t.HelloWorld(this));
You can call the BeginInvoke method, which will queue a delegate to be executed asynchronously on the UI thread.
If you need the background thread to wait until the function finishes on the UI thread, you can call Invoke instead.
Note that you will need a reference to the instance of your form; you should probably pass that to the Test constructor and store it in a private field.
The BackgroundWorker component will do all of this automatically using the ReportProgress method; you should consider using it.
The prefered way in WinForms is to use the SynchronizationContext
public partial class MainForm : Form
{
SynchronizationContext ctx;
public MainForm()
{
ctx = SynchronizationContext.Current;
Test t = new Test();
Thread testThread = new Thread(new ThreadStart(t.HelloWorld));
testThread.IsBackground = true;
testThread.Start();
}
private void UpdateTextBox(string text)
{
ctx.Send(delegate(object state)
{
textBox1.AppendText(text + "\r\n");
},null);
}
}
public class Test
{
public void HelloWorld()
{
MainForm.UpdateTextBox("Hello World");
// How do I excute this on the main thread ???
}
}

WPF Dispatcher and Running it in background

I tried to wrap the dispatcher in a thread. But the result is not what i expect. How can i solve that problem?
public void Start()
{
ThreadStart ts = inner;
Thread wrapper = new Thread(ts);
wrapper.Start();
}
private void inner()
{
_Runner.Dispatcher.Invoke(_Runner.Action, DispatcherPriority.Normal);
}
You have not shown us enough code/explained yourself well enough to be able to provide a good answer, but I'm guessing your action (_Runner.Action) is expensive and slow to execute. If so, that is why your UI is unresponsive. You're essentially telling the Dispatcher to run that expensive operation on the UI thread when what you really want to do is run as much of your operation on the background thread as possible, and then marshal back to the UI thread via the Dispatcher only when necessary.
When you fire an action through/on the dispatcher, that action is called on the UI thread.
My guess is that you are doing the work/processing in the _Runner.Action function and it is tying up the UI thread. You'll have to do the main processing part in the inner() function and then call the Dispatcher for the final update details.
If you absolutely must process on the dispatcher, break your process into smaller pieces and call Dispatcher.BeginInvoke() for each piece so other events can be processed in between your process.
You need to break Runner.Action into two parts - the long running part that does the calculation and the part that updates the GUI.
After you do that you call the long running part in the background thread and use the dispatcher only on the UI update part.
By the way, you should also probably use BeginInvoke and not Invoke.
If the long running part of Runner.Action is updating the GUI than you can't use a background thread to solve your problem - there are solutions for slow GUI operations but they change depending on what exactly you are trying to do.
Here is an example that will let you run WPF applications with multiple UI threads. I believe this will help you. Refer to this http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/
Thread lThread = new Thread(() =>
{
var lWnd = new Window1();
lWnd.Show();
lWnd.Closed += (sender2, e2) => lWnd.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
lThread.SetApartmentState(ApartmentState.STA);
lThread.Start();
Ditto what everyone here has said.
Additionally, you may want to look into using the BackgroundWorker class.
This is what I have started using for background tasks... I have not been using it long, so I don't know if there are bugs.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SSA.Utility
{
public class BackgroundTaskManager : IDisposable
{
private System.Windows.Threading.Dispatcher _OwnerDispatcher;
private System.Windows.Threading.Dispatcher _WorkerDispatcher;
private System.Threading.Thread _WorkerThread;
private Boolean _WorkerBusy;
private System.Threading.EventWaitHandle _WorkerStarted = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset);
public BackgroundTaskManager()
{
_OwnerDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
_WorkerThread = new System.Threading.Thread(new System.Threading.ThreadStart(WorkerStart));
_WorkerThread.Name = "BackgroundTaskManager:" + DateTime.Now.Ticks.ToString();
_WorkerThread.IsBackground = true;
_WorkerThread.Start();
_WorkerStarted.WaitOne();
}
public Boolean IsBusy
{
get { return _WorkerBusy; }
}
public System.Windows.Threading.Dispatcher Dispatcher
{
get {
return _WorkerDispatcher;
}
}
public System.Windows.Threading.Dispatcher OwnerDispatcher
{
get
{
return _OwnerDispatcher;
}
}
private void WorkerStart()
{
_WorkerDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
_WorkerDispatcher.Hooks.DispatcherInactive += WorkDone;
_WorkerDispatcher.Hooks.OperationPosted += WorkAdded;
_WorkerStarted.Set();
System.Windows.Threading.Dispatcher.Run();
}
private void WorkAdded(Object sender, System.Windows.Threading.DispatcherHookEventArgs e)
{
_WorkerBusy = true;
}
private void WorkDone(Object sender, EventArgs e)
{
_WorkerBusy = false;
}
public void Dispose()
{
if (_WorkerDispatcher != null)
{
_WorkerDispatcher.InvokeShutdown();
_WorkerDispatcher = null;
}
}
}
}
// Useage (not tested)
private SSA.Utility.BackgroundTaskManager _background = new SSA.Utility.BackgroundTaskManager();
public void LongTaskAsync()
{
_background.Dispatcher.BeginInvoke(new Action(LongTask), null);
}
public void LongTask()
{
System.Threading.Thread.Sleep(10000); // simulate a long task
_background.OwnerDispatcher.BeginInvoke(new Action<STATUSCLASS>(LongTaskUpdate), statusobject);
}
public void LongTaskUpdate(STATUSCLASS statusobject) {
}
Yes. _Runner.Action is the problem. Some long-timed methods used in the Dispatcher block. But solution is "dont use the any thread not related to UI in the dispatcher"

How to Create Form from within non gui thread C#

I have my main GUI from where I start a long running method in a separate thread.
Now from within this separate thread I need to create and show a new form.
But when I show this new form all the controls are stuck an the window says "not responding".
Which is the best way of solving this ??
regards
Thomas
Put the code that creates the new GUI into the main GUI class and then call the main GUI's Invoke method, or raise an event that the main GUI can subscribe to to know when to trigger the new GUI. If you choose the latter, be sure to use InvokeRequired to determine if you can call the method that creates the new GUI directly or if you need to use an Invoke to get back onto the GUI thread to create the new GUI.
You need to learn about Control.BeginInvoke/Invoke and all that means. Just remember that all UI operations need to occur on the main thread (UI thread) because that is the thread that owns the message pump. You need to call back into that thread in order to have UI actions happen.
Here's an intro to the BeginInvoke/Invoke stuff: http://weblogs.asp.net/justin_rogers/pages/126345.aspx
In order to help further here's a complete working code example that should highlight the basics.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var worker = new Worker(this);
worker.Start();
}
public void updateLabel(int value)
{
if(label1.InvokeRequired) { // check if on UI thread
//If true use begin invoke to call update on UI thread
//this calls the anonymous delegate in the UI thread
//that then calls the updateLabel function again to set the label's text
label1.BeginInvoke(new MethodInvoker(() => this.updateLabel(value)));
return;
}
label1.Text = value.ToString();
}
public void showNewForm()
{
if(this.InvokeRequired) { // check if on UI thread
this.BeginInvoke(new MethodInvoker(this.showNewForm)); // we need to create the new form on the UI thread
return;
}
var anotherForm = new Form1();
anotherForm.Show();
}
}
class Worker
{
private volatile bool stop = false;
private Form1 form;
public Worker(Form1 form)
{
this.form = form;
}
public bool Stop
{
get
{
return stop;
}
set
{
stop = value;
}
}
public void Start()
{
var thread = new Thread(this.work);
thread.IsBackground = true;
thread.Start();
}
private void work()
{
int i = 0;
while(!stop) {
i++;
Thread.Sleep(100);
form.updateLabel(i);
if(i == 50) {
form.showNewForm(); // call into form
// can also do the invokerequired check here and create new form w/ anonymous functions
// however, I'd recommend keeping all the UI code in the same place.
}
}
}
}
Use Form.Show instead of Form.ShowDialog. You can also use a BackgroundWorker to do concurrent tasks.

Categories

Resources