I have a Server class which it basically waits for connections from a client. Inside that class I create an NetworkStream object in order to be able to receive bytes from a client. Because the NetworkStream.Read() method is not asynchronous (meaning that it will wait until it reads bytes from a client in order to proceed executing code similar to the messagebox method), I have to read for bytes in a separate thread so that the user using the program can still interact with the program if the program happens to be waiting to read for data.
anyways a lot of objects are owned by that thread. One example is that I have a List called log in that class. I use that list to know the status of the server. Maybe it is listening for a connection or perhaps it's status is "connected" or "disconnected".
So if I do something like:
Server myServer = new Server("192.168.0.120","1300"...\\ I pass the appropite parameters in order to instantiate it
//...
.. then I am able to latter look at the log as
string foo = myServer.Log[0] for example.
because I want to know when the log is updated, on the server class I have created an event as:
public delegate void onUpdateHandler(string newStatus);
public event onUpdateHandler onUpdate = delegate { };
I then fire events on the Server class as:
onUpdate("waitingForConnection");
and I receive those events with the method:
but if I try to do something with newStatus I get the error stating:
System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
so how can I pass an object with an event?
Edit
so I also notice that if I do:
I also get an error!
but when I do the same thing calling that from a button as:
// SERVER IS RUNNING BEFORE CALLING THIS METHOD
private void button3_Click(object sender, RoutedEventArgs e)
{
listView1.Items.Add("my own string");
}
I do NOT get an error!
why is it that I get an error with the event and I do not get an error when calling it with a regular button.
The problem is that the thread tries to access the ListView which is a DependencyObject which has thread affinity, use the Dispatcher to execute methods like this on the UI-thread, e.g.:
Application.Current.Dispatcher.Invoke((Action)(() =>
{
listView1.Items.Add(newStatus);
}));
Also see the threading model reference for additional info.
The problem is not that you try to do something with the value that you sent to the method, the problem is what you are trying to do with it.
The event handler is still running in your background thread, and from there you can't use any UI controls as they belong to the main thread.
The usual way of handling that is to use the CheckAccess method to check if you need to switch treads, and the Invoke method to hand off the work to the main thread:
void server_onUpdate(string newStatus) {
if (!listView1.Dispatcher.CheckAccess()) {
listView1.Dispatcher.Invoke(server_onUpdate, newStatus)
} else {
listView1.Items.Add(newStatus);
}
}
Related
First of all my Main is STAThread and i am not able to change this without facing problems with the rest of my code.
So, I am currently using Rapi2 To pull and push files between my Pda and Computer. Now since there is quite a bit of number crunching i would like to do this on a separate thread. First wat i do is create an RemoteDeviceManager and then make an Event Handler for when a device connects.
public void Initialize()
{
_deviceManager = new RemoteDeviceManager();
_deviceManager.DeviceConnected += DeviceConnected;
}
As you can see when my device connects it triggers DeviceConnected.
This is the class that i end up pulling and pushing a database and do some number work.
private void DeviceConnected(object sender, RemoteDeviceConnectEventArgs e)
{
if (e.Device == null) return;
... (unimportant code)
}
Now the problem here is that i would want to run the code inside DeviceConnected in a new thread but i am unable to access e inside the new thread since it was initialized outside that thread
So now wat i tried was make a new thread before calling Initialize.
public Watcher()
{
_dataThread = new Thread(Initialize);
_dataThread.IsBackground = true;
_dataThread.Name = "Data Thread";
_dataThread.SetApartmentState(ApartmentState.MTA);
_dataThread.Start();
}
But the thread dies and thus never fires my event handler.
I tried many different ways to make it work or keep my thread alive but without any success. I hope someone here is able to give me some hints.
I'm using C# and Winforms in Visual Studio 2010
I have a program with which I am trying to read output through a serial port and print it to the screen. It originally started as a Console program but has now evolved to where we would like to have the output be in a field on a form. I have the code that parses out the output I'm looking for off the serial port written and working, I just need to change the Console.WriteLine to label.text = "";, basically. I have merged the function that listens to the serial port into the GUI code so everything is in the same file.
I'm getting hung up on how to get the function to write to the label, though. It is STATIC so I cant just say 'label.text ='. I tried creating a new form object inside the function to use, and that allowed me to access the control on the form, but doesnt update the form I see at runtime (I'm guessing because I've created a new instance of the form rather than accessed the existing instance?)
I need to have the serial listener run at the same time as the GUI as well, so the GUI label will update with the results it gets from running the function in close to real-time, so Ive tried to set it up to be threaded, with the GUI being one thread that is started by main() and the serial listener being another thread which is started when i click the button to start it. However, I run into the same issue with not being able to access the label in the serial listener thread because it has to be static to be initialized using system.threading.
I'm thinking maybe I need to use a background worker for the serial listener but I have absolutely zero experience with those. Would a background worker be able to update the label on the GUI in real time?
I cant post specific code but heres the general idea:
Main() starts GUIthread
GUI has button to start serial listener
OnClick button starts ListenerThread
ListenerThread outputs to console, want to output to a form label instead
Cant access GUI.Label because Listener is static out of necessity to be threaded
Creating new GUI instance inside Listener allows me to call the controls for that instance, but they dont update the GUI at runtime
have ensured label is public.
The BackgroundWorker class was essentially made just for this.
Just have the DoWork method do your actual work, and ensure that ReportProgess is called while working as needed. You can pass any data as a string (or whatever else, if you want) and then use that value in the ProgressChanged event handler, which the form can handle to update it's UI.
Note that the BackgroundWorker will automatically ensure that the ProgressChanged and RunWorkerCompleted events run in the UI thread, so you don't need to bother with that.
Here's a sample worker:
public class MyWorker//TODO give better name
{
public void DoWork(BackgroundWorker worker)//TODO give better name
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(1000);//to mimic real work
worker.ReportProgress(0, i.ToString());
}
}
}
And here's an example of configuring the background worker. Here I use lambdas both because it's convenient to be able to close over variables (i.e. use variables across each of these anonymous methods) but if you wanted to you could refactor each of the event handlers out into methods.
private void button1_Click(object sender, EventArgs e)
{
var bgw = new BackgroundWorker();
MyWorker worker = new MyWorker();
bgw.WorkerReportsProgress = true;
bgw.DoWork += (s, args) => { worker.DoWork(bgw); };
bgw.ProgressChanged += (s, data) =>
{
label1.Text = data.UserState.ToString();
};
bgw.RunWorkerCompleted += (s, args) =>
{
label1.Text = "All Done!";
};
bgw.RunWorkerAsync();//actually start the worker
}
Note here that none of the controls in the form are public, none of them are static, and I'm not passing any references to my form outside of the class. It's considered best form each Form to be responsible for updating it's own Controls. You shouldn't be allowing anyone else to directly access them. Rather than allowing some other worker class to directly access the label or modify it's text, what's happening is that the worker is simply telling the form, "Hey, I've got some data, you can go update yourself accordingly based on these values." It is then the form that is responsible for updating itself. events are what you use to allow these workers, or other types of child elements (such as other forms you create, for example) to inform the "parent" form that it needs to update itself.
To write to any windows control, you must be on the UI thread. If you have a serial listener running on a different thread, then you need to switch threads before changing the windows control. The BeginInvoke can be handy, http://msdn.microsoft.com/en-us/library/system.windows.forms.control.begininvoke.aspx.
What I would do, is add a Action to the serial listener that is called whenever the listener wants to display something. And then this Action would call BeginInvoke.
Something like:
static class SerialListner
{
public Action<string> SomethingToDisplay;
void GotSomethingToDisplay(string s)
{
SomethingToDisplay(s);
}
And then somewhere in your windows form
SerialListern.SomethingToDisplay = (s) =>
label.BeginInvoke((Action) () => label.Text = s);
I think you can use a background worker, and they are really easy to use.
In order to use a BackgroundWorker, you'll have to implement at least two events:
backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
there you read your input. It's triggered calling backgroundWorker1.RunWorkerAsync(...)
backgroundWorker1_ProgressChanged(....)
there you update your label. Maybe you'll have to create a delegate to update it.
you can also implement:
backgroundWorker1_RunWorkerCompleted(....)
to let you know when it stop...
Going on what you said about a static listener method and that it used to be a console application, I think a relatively minor modification might be the following:
class Program
{
static void Main(string[] args)
{
// Create a main window GUI
Form1 form1 = new Form1();
// Create a thread to listen concurrently to the GUI thread
Thread listenerThread = new Thread(new ParameterizedThreadStart(Listener));
listenerThread.IsBackground = true;
listenerThread.Start(form1);
// Run the form
System.Windows.Forms.Application.Run(form1);
}
static void Listener(object formObject)
{
Form1 form = (Form1)formObject;
// Do whatever we need to do
while (true)
{
Thread.Sleep(1000);
form.AddLineToTextBox("Hello");
}
}
}
In this case, Form1 is obviously the form class, and Listener is the listening method. The key here is that I'm passing the form object as an argument to the Listen method (via Thread.Start), so that the listener can access the non-static members of the GUI. Note that I've defined Form1.AddLineToTextBox as:
public void AddLineToTextBox(string line)
{
if (textBox1.InvokeRequired)
textBox1.Invoke(new Action(() => { textBox1.Text += line + Environment.NewLine; }));
else
textBox1.Text += line + Environment.NewLine;
}
Note especially that since now the Listener method is running in a separate thread, you need to use the Invoke method on the GUI control to make a change. I've used a lambda expression here, but if you're targeting an earlier version of .net you could use a full method just as easily. Note that my textBox1 is a TextBox with Multiline set to true and ReadOnly set to false (to be similar to a label).
An alternative architecture which may require more work but would probably be more elegant would be to do the opposite dependence relationship: you create the form with a reference to a Listener object. The listener will then raise events which the GUI would be subscribed to in order to update its display.
I have a WPF application where the user enters database information in some textboxes. Once the user clicks "connect", a connection string is created from what the user had entered and a connection is established. I noticed that if the user enters any info that is wrong, the application will hang until the connection times out. By hang, I mean the user can't interact with the rest of the application at all.
It is my goal to keep the application responsive while the connection string is tested.
I thought that putting this workflow on a different thread is a good solution. My idea is to just disable anything that may need a database connection while the thread runs. Once the thread comes back (and has has confirmed the connection string to be valid) I would re-enable everything. Otherwise, leave everything disabled.
However, the Thread class doesn't have an event notification when the thread is done (or at least I am unaware of one).
I have also worked with the BackgroundWorker class. This works better. However, when the RunWorkerCompletedEventHandler event is fired and the connection string isn't valid, I get the following exception:
The calling thread cannot access this object because a different
thread owns it.
This is probably because the connection still hasn't timed out when the completed event handler is fired.
Does anybody have any ideas, or should I just NOT try to multithread a connection to a database?
A code outline of what I am doing:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
dbTool = new DBTool();
// Create the connection string
e.Result = dbTool.connectToDB(); // connectToDB() returns a bool (true if connection established)
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// connectToDB() returns a bool (true if connection established)
if(e.Result == true) // Trying to read e.Result here throws the exception
{
// e.Error and e.Cancel should be checked first
// However, I would like the thread to finish before
// this event is fired
}
if (e.Error != null)
{
Console.WriteLine(e.Error.Message);
}
}
Don't preserve your DbConnection object in a single global variable and share it between threads.
The .NET environment will automatically pool your connections and share them, so calling new DbConnection() is very fast.
You should keep the connection string in a global variable, but then create connections as required on each thread.
EDIT: The original poster may have actually wanted ideas on how to keep the WinForms application responsive while a connection string is being tested. In that case, you want to spawn a different thread to test the connection. From the "connection test thread," you can update the UI by following this pattern - How to update the GUI from another thread in C#?
public void TestConnectionThread(String connstr_to_test)
{
// Notify the user that we're doing our test
string message = "Testing...";
lblTestResultMessage.SetPropertyThreadSafe(() => lblTestResultMessage.Text, message);
try {
dbTool = new DBTool();
message = dbTool.connectToDB();
// If something failed, show a useful debugging message
} catch (Exception ex) {
message = ex.ToString();
}
// Use a lambda expression to communicate results to the user safely
lblTestResultMessage.SetPropertyThreadSafe(() => lblTestResultMessage.Text, message);
}
From DBConnection's documentation:
Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
In other words, different threads should never share a database connection, because the instance cannot safely be shared. As Ted Spence suggests, you should instead create connections only as you need them (and .Dispose() them when you're done with them). .NET has a built in connection pooling mechanism that does a very good job of making sure connections are reused when possible, but holding onto connections any longer than is absolutely necessary can interfere with its ability to do that.
try
dbtool tool = e.result as dbtool;
If you have a variable in dbTool that that gets set to true or false when the query completes then you should be able to call
tool.variable = true/false
Thank you everyone for your input.
I was able to come up with a solution. After coming across Working With The WPF Dispatcher. I determined that you can obtain the UI thread's Dispatcher object:
//...
dbTool = new DBTool();
// Initialize the connection string
// Disable some UI
Thread thread = new Thread(new ThreadStart(
delegate()
{
dbTool.connectToDB();
UIControl.Dispatcher.BeginInvoke(
new Action(
update
));
}
));
thread.Start();
//.....
void update()
{
if (dbTool.validString) // If the connection string was valid
{
// Re-enable controls
}
else // Invalid connection string
{
// Keep controls disabled if no connection could be created
}
}
This indeed will test the connection string on a different thread, leaving the rest of the application responsive.
I'm using a timer to regularly read-in a log file and post certain contents to a textbox in a Windows Form Application I'm developing in C#. I do this by sending a string to set_textbox_thread which posts the text (s) to the appropriate textbox (tbc) in the else below. The code below works in the practice application I built. However, the same code runs, but fails to update my textbox in the full application I'm building. It seems to be failing on the Invoke statement, which fails to call set_textbox_thread again. My theory is that, because my full application has a more complex set of controls, I am not calling Invoke via the correct control. I've tried calling it via "this" the parent panel, the parent form, and the button that triggers set_textbox_thread, and am dealing with the same outcome. Two questions:
Which control should I call Invoke under?
Is there a way to retrieve "the thread that owns the controls underlying windows handle? Can I do this through the Controls.Owner method?
I have tried making this Invoke call using try/catch, but am unable to retrieve an error message in the catch. Any ideas how to resolve the issue this way?
Thanks in advance!
private delegate void stringDelegate(string s);
private void set_textbox_thread(string s)
{
TextBox tbc = get_thread_tb();
if (tbc.InvokeRequired)
{
MessageBox.Show("Invoke Required");
stringDelegate sd = new stringDelegate(set_textbox_thread);
**this.Invoke(sd, new object[] {s });**
MessageBox.Show("Invoke Completed");
}
else
{
1) It doesn't matter what control you invoke under; there is only one UI thread and any control to marshal the call back to that UI thread.
2) what could you possibly do with this thread?
3) not much detail there. How do you know you have error messages? And what do you mean by "error messages"
Call invoke on the text box instead:
tbc.Invoke(sd, new object[] {s });
I have a server application that receives information over a network and processes it.
The server is multi-threaded and handles multiple sockets at time, and threads are created without my control through BeginInvoke and EndInvoke style methods, which are chained by corresponding callback functions.
I'm trying to create a form, in addition to the main GUI, that displays a ListBox item populated by items describing the currently connected sockets.
So, what I'm basically trying to do is add an item to the ListBox using its Add() function, from the thread the appropriate callback function is running on.
I'm accessing my forms controls through the Controls property - I.E:
(ListBox)c.Controls["listBox1"].Items.Add();
Naturally I don't just call the function, I've tried several ways I've found here and on the web to communicate between threads, including MethodInvoker, using a delegate, in combination with Invoke(), BeginInvoke() etc.
Nothing seems to work, I always get the same exception telling me my control was accessed from a thread other than the one it was created on.
Any thoughts?
I've always used something along these lines:
c = <your control>
if (c.InvokeRequired)
{
c.BeginInvoke((MethodInvoker)delegate
{
//do something with c
});
}
else
{
//do something with c
}
I also wrote a bunch of helper extension methods to... help.
using System;
using System.ComponentModel;
public static class CrossThreadHelper
{
public static bool CrossThread<T,R>(this ISynchronizeInvoke value, Action<T, R> action, T sender, R e)
{
if (value.InvokeRequired)
{
value.BeginInvoke(action, new object[] { sender, e });
}
return value.InvokeRequired;
}
}
used like this:
private void OnServerMessageReceived(object sender, ClientStateArgs e)
{
if (this.CrossThread((se, ev) => OnServerMessageReceived(se, ev), sender, e)) return;
this.statusTextBox.Text += string.Format("Message Received From: {0}\r\n", e.ClientState);
}
You have to call Invoke (or BeginInvoke) on the ListBox control you are accessing in order for the delegate to be called on the thread that created that control.
ListBox listBox = c.Controls["listBox1"] as ListBox;
if(listBox != null)
{
listBox.Invoke(...);
}
Using BeginInvoke or Invoke should work fine. Could you post a short but complete program which demonstrates the problem? You should be able to work one up which doesn't actually need any server-side stuff - just have a bunch of threads which "pretend" to receive incoming connections.