i writed a program with Serial Port as this:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
serialLabel.BackColor = Color.Red;
storage = serialPort1.ReadExisting();
if (storage.Contains("CMGL"))
{
if (storage.Length > 65)
{
processUnreadedMessages(storage);
}
else
{
Thread.Sleep(500);
}
}
else if (storage.Contains("CMTI"))
{
serialPort1.Write("AT+CMGL\r");
Thread.Sleep(500);
}
storage = "";
serialLabel.BackColor = Color.Lime;
}
in visual studio when i run program works good!
but when i'l create setup for my program or run exe file, data don't receive to serialPort, and i don't get any error. but when i send data with this program it's work!
can you help Me?
the problematic lines are probably those:
serialLabel.BackColor = Color.Red;
and
serialLabel.BackColor = Color.Lime;
there's a slim chance it will still work in developent environment, but:
The DataReceived event is raised on a secondary thread when data is
received from the SerialPort object. Because this event is raised on a
secondary thread, and not the main thread, attempting to modify some
elements in the main thread, such as UI elements, could raise a
threading exception. If it is necessary to modify elements in the main
Form or Control, post change requests back using Invoke, which will do
the work on the proper thread.
[msdn]
try instead:
serialLabel.Invoke(new EventHandler(delegate
{
serialLabel.BackColor = Color.Red;
}));
Also:
make sure you don't touch GUI or anything that should be accessed from the thread it was created on without invoking (e.g. you also shouldn't write data to EventLog without Invoking) in your method processUnreadedMessages()
Check if there's no First Chance exceptions when you debug your application
check Application EventLog for messages generated by your application.
log data you received in serialPort1_DataReceived event to a file before you do anything else (this will check if DataReceived event is raised at all when it should)
subscribe to SerialPort.ErrorReceived event
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.
Please excuse me if this is redundant, however all the questions related to this seem to point in different directions, also I am new to multithreaded programming.
I have a FileSystemWatcher class in my code, which watches the created event. It looks like a created event of file system watcher starts it's own thread. So sometimes the calling thread continues it's work before the work initiated in called thread of FileSystemWatcher created event finishes. I don't want this. My workflow needs to be single-threaded, so what I want to achieve is wait for for created event to finish it's work before the calling thread gets an opportunity to resume.
pesudo code:
main() {
FileSystemWatcher fsw = new FileSystemWatcher()
fsw.Path = ini.location;
fsw.Created += new FileSystemEventHandler(OnFileCreation);
fsw.EnableRaisingEvents = true;
main_engine.processDataToFile();
main_engine.processCreatedFile();
}
void OnFileCreation(object sender, FileSystemEventArgs e) {
// do some file processing
// takes time based on size of file and whether file is locked or not etc.
}
void processDataToFile() {
// do some data processing on received data and output to a file.
}
void processCreatedFile() {
// do not want this method to be called, unless OnFileCreation() finish it's work.
}
The reason choose to use FileSystemWatcher was because sometimes files are directly placed for processing instead of main_engine getting the data first and it works on multiple locations, so did not want to roll out a homegrown solution when FileSystemWatcher was available.
If the event fires in the separate thread you cant make it single-threaded. because this is not your code. end of story.
however it is quite simple to wait on:
...
me.WaitOne();
main_engine.processCreatedFile();
}
...
void OnFileCreation(object sender, FileSystemEventArgs e) {
// do some file processing
// takes time based on size of file and whether file is locked or not etc.
...
me.Set();
}
ManualResetEventSlim me = new ManualResetEventSlim(false);
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.
Part of my program uses an event handler for the receive data of my serial port. The idea is when data is received that the text received is then added to the textbox (rx). I did not used to have this problem but something has changed and I can't figure out what. So now I am re-examining the way this is handled.
During the form load of my winform the last thing I do is
if (!serialPort1.IsOpen)
{
serialPort1.Open();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}
Then I have the event handler
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
string indata1 = serialPort1.ReadExisting();
// rx.Text = " "; accidentally posted this. it was from trial and error.
rx.AppendText(Environment.NewLine + indata1);
}
When I run the program it stops at the rx.AppendText(Environment.NewLine + indata1); and gives the error
invalidoperationexception was unhandled: Control "accessed from a
thread other than the thread it was created on.
From what I have been able to read suggests that I need to use invoke or BeginInvoke.
I have never had problems appending the text before so now I can't understand why it's a problem. Also from what I have been reading on invoking i just don't understand it.
Can someone help me understand how to use the invoke instance for my situation? or perhaps show me another way of appending the text box?
Usually the exception you're seeing occurs when you run in debug mode, and if you run your application in release mode, you're unlikely to see the exception.
However, it is best to use invoke, as you have read. Something like this:
private delegate void RefreshTextBox();
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) {
//this event is raised in an event separate from UI thread,
//so InvokeRequired must be checked and Invoke called to update UI controls.
if (this.InvokeRequired) {
RefreshTextBox d = new RefreshTextBox(RefreshTextBoxResults);
Invoke(d);
} else {
RefreshTextBoxResults();
}
}
private void RefreshTextBoxResults() {
string indata1 = serialPort1.ReadExisting();
rx.Text = " ";
rx.AppendText(Environment.NewLine + indata1);
}
The first time you see this invoke stuff, it's nearly impossible to follow, but take a close look and give it some time and it will make sense. Promise. :)
Updates in GUI applications should only be done on the GUI thread. Another thread attempting to update GUI components directly will result in either the error you described or in seemingly random behavior.
The role of Invoke & friends is to enable a secondary thread to safely forward GUI updates to the GUI thread, which will then process them from a queue.
In your case (assuming WinForms here):
rx.BeginInvoke(
(Action)(() =>
{
rx.AppendText(Environment.NewLine + indata1);
}));
BeginInvoke is asynchronous, so the thread calling it will not wait for the actual updates to be processed before moving on, while Invoke is synchronous.
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.