My project have a MainForm, i show F_Insert and set MdiParent for MainForm
F_Insert f = new F_Insert();
f.MdiParent = this;
f.Show();
In F_Insert, i put a button with CLick event like this
private void btn_Add_Click(object sender, EventArgs e)
{
//Insert data to SQL
}
Besides, i want to auto upload data that inserted from F_Insert every 5 second
I use System.Timer.Timer and set it to Thread in MainForm_Load
Thread t1 = new Thread(new ThreadStart(Timerss)); //In MainFormLoad event
t1.Start();
public void Timerss()
{
System.Timers.Timer timer = new System.Timers.Timer(5000);
timer.Elapsed += Timer_Insert_Tick;
timer.AutoReset = true;
timer.Start();
}
private static void Timer_Insert_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
//code auto upload data to server here
//Data get from Sql Local to upload SQL in Server
}
The problem is it's not working good. I feel when i insert data form F_Insert, data is affected by Timerss thread that i start in MainForm load.
The simple way to show you my problem: when i split two work (Insert
and upload) into 2 difference work, it working good, it's mean i'm
insert data complete and then, i upload data, it will working good.
But when i insert data and data auto upload by timer in the same time,
i see some error that: conection sql close or open error, no data get
from F_Insert, sometime it get duplicate data (old data)
Please suggeted me some idea for this problem. Sorry but i'm newbie in thread. Thank you !!!
Well depending on what you trying to do this code should be modified but i hope it'll give you starting point to work with.
First of all let's create static field:
static volatile bool isDataChanged;
Keyword volatile makes this bool thread-safe, it means that this field always holds latest (and therefore correct) value when it is accessed by any thread in multi-thread environment).
We need this field to hold bool value that is used later to check whether the data was modified or not.
Assuming that data is modified inside click event handler, we should set this flag to true :
private void btn_Add_Click(object sender, EventArgs e)
{
// Data is modified in UI thread
isDataChanged = true;
}
Then let's assume that in Timer tick event we should upload the latest data to database (data is located in UI thread and could change in time span in between two tick events).
First of all we check if there is any changes to our data and if there's not we just exits the method. If changes was done we need to upload them to DB and in order to do so we have to deal with the fact that data in Timer thread could very well not be the same as data in our UI thread.
Let's create local variable that will hold correct data that we fetch from UI thread and use this.Invoke() to invoke Func<object> delegate on UI thread. The method that is attached to delegate returns instance of correct data retrieved from UI thread as object. We cast it explicitly to the type that our data is (usually it's one of collection types like List<T> or Dictionary<T1, T2>) and use this data to upload it to the DB.
After that, because our data in DB is the correct one, we change flag isDataChanged to false.
private void Timer_Insert_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
if(!isDataChanged) return;
// A very important line. It gets data from UI thread before uploading it
// Change DataType with your data Type and dataToUpload with data instance
DataType data = (DataType)this.Invoke(new Func<object>(() => dataToUpload));
//use data to upload your data to server
isDataChanged = false;
}
P.S.
Also it is better to place reference to our Timer in outer scope (so it can be accessed from anywhere inside the form)
public partial class MyForm : Form
{
...
System.Timers.Timer timer;
public void Timerss()
{
timer = new System.Timers.Timer(5000);
}
...
}
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 am already using backgroundworker.RunAsyn() to run my code on a separate thread. However I am hitting a portion where the code iterates to the next line before the previous line is completed. Should I create a separate backgroundworker to handle that? Or should I use Application.Wait() or Thread.Sleep() I am not sure the amount of time to delay and I'd rather not have my program just sitting around waiting for extra un-needed time so I am not sure which route to take. Here is a snippet of the trouble-maker.
public Form_Main()
{
InitializeComponent();
backgroundworker1.WorkerReportsProgress = true;
backgroundworker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1_ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
}
private void btnOpenRefreshSave_Click()
{
backgroundWorker1_RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Excel.Application exApp;
Excel._Workbook exBook;
Excel._Worksheet exSheet;
exBook = (Excel._Workbook)(exApp.WOrkbooks.Open("C:\\Book1.xlsx"));
exSheet = (Excel._Worksheet)(exBook.ActiveSheet);
//This is the line of code that often times takes a while
exBook.RefreshAll();
//end of trouble line
exBook.SaveAs("C:\\Updated_Book1.xlsx");
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
A few things come to mind on what to do here. You could try using something similar to the below
if (Application.CalculationState === xlDone Then
everything is finished calculating[enter link description here][1]
Another option would be (as others have suggested) changing the background refresh property. A quick scan of the workbooks could programmatically change that for you
foreach (Wrksheet ws in workbook.wss)
{
foreach (QueryTable table in ws.QueryTables)
table.BackgroundQuery = false;
}
workbook.RefreshAll();
The problem is caused because RefreshAll is running on a background thread. So basically you have your own backgroundworker running and another one you did not anticipate for.
The documentation for refreshAll says :
Objects that have the BackgroundQuery property set to true are refreshed in the background.
So you can get out of this problem only be setting that property to false. Then the refreshall would run in the context of your backgroundworker which is what your intent is.
If this still does not work, then you have to rethink your logic and look for an event of some kind that is triggered when the refresh is done. If this does not exist, then there is no solution other than a sleep, but that is not a good solution at all because you don't know how long to sleep.
Why do you want to delay something, can't you do saving your workbook on one of its events like SheetCalculate (Occurs after any worksheet is recalculated or after any changed data is plotted on a chart) and setting some flag in your code and reset that on that event (or any more relevant event)
I just received a bug list for an old app developed yeah years ago and one of the things i need to sort out is the amount of time it takes to load data into one screen,of course, while the screen is frozen and unfortunately this is in WinForms .NET 4.5. The data is loaded into a WinForms DataGridView. I would like to find out if there is any way of loading this data using C# 5 async and await,while refreshing the grid to add the next set of data. It may be while scrolling or in the background.Any ideas?
Try loading all of the data into an array from an asynchronous thread and then using Invoke to insert the array into the DataGridView.
Call this from Form_Load
new Thread(new ThreadStart(Run)).Start();
then create this method
private void Run()
{
//DataArray
//Load Everything into the DataArray
Invoke(new EventHandler(delegate(object sender, EventArgs e)
{
//Load DataArray into DataGridView
}), new object[2] { this, null });
}
This I believe is the most optimized way to load something into a Control since Controls are not allowed to be touched outside of the MainThread. I don't know why Microsoft enforces this but they do. There may be a way to modify Controls outside of the MainThread using Reflection.
You could additionally slowly load the data into DataGridView. It will take longer to load all of the data but it will allow you to continue to use the Form while it is loading.
private void Run()
{
//DataArray
//Load Everything into the DataArray
for(/*Everything in the DataArray*/)
{
Invoke(new EventHandler(delegate(object sender, EventArgs e)
{
//Load 1 item from DataArray into DataGridView
}), new object[2] { this, null });
Thread.Sleep(1); //This number may have to be tweeked
}
}
You want to use virtual mode. Other solutions do all the upfront work to load the data and then put it into the grid (which still gives you a startup delay), or else they add chunks of data at a time (which messes up your scrolling).
Virtual mode reverses this; instead of you throwing your data at the grid, virtual mode will have the grid request your data.
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 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);
}
}