Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Using Winforms, C#, FW 4.5.
I have a simple form with a textbox and a gridView.
When I start a new task, it's able to access the cells of the grid and change the text. When I try to change the textbox text i get this error "cross thread operation not valid..."
Both the textbox and the gridView are on the same form. Why the behavior is different?
It is generally a bad idea to access your UI from a different thread than the one which started the UI. It is possible to avoid the exception by setting the static property Control.CheckForIllegalCrossThreadCalls to false, but that is a very dangerous way.
You should rather use Control.BeginInvoke to defer execution back to the UI thread.
So you could replace your line txtSql.Text = sQuery to something like that:
void RunChecks()
{
...
SetQueryText(sQuery); // instead of txtSql.Text = sQuery;
...
}
delegate void SetTextDelegate(string text);
void SetQueryText(string query)
{
if (txtSql.InvokeRequired)
{
txtSql.BeginInvoke(new SetTextDelegate(SetQueryText), query);
return;
}
txtSql.Text = query;
}
So SetQueryText checks if it is necessary to call Invoke (or BeginInvoke) because it was called from another thread. If this is the case, it calls BeginInvoke to defer execution to the UI thread and returns.
Unfortunatly this still uses the delegate syntax instead of lambdas, but maybe there's a better syntax that I just don't know.
You need to do this for all controls you are accessing from different threads.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I am retrieving data of about 100k rows from a database into a datagridview.This process takes up to 5-6 seconds.however during these seconds the user can't move the mouse or click any other button.how can I use aysnc/multithreading to achieve smooth user interface.
Look into the Task library and async, there's a whole section of C# for doing exactly this.
Basically you wind up with things like . . .
var records = await GetRecordsFromDatabase();
MyDataGridView.ItemSource = records;
private Task<IEnumerable<Record>> GetRecordsFromDatabase(){
return Task.Run(() => {
//do stuff the return IEnumerable<Records>
});
}
Note that while you can use threads, Tasks are a much better option in C# for async support.
Edit - most databases should support some async operation. In that case you'd likely have an async method to transform things from the database to the format you need. You'd also likely want to follow the convention of marking your own method as async. Something like . . . .
private async Task<IEnumerable<Record>> GetRecordsFromDatabaseAsync(){
var dbRecords = await Database.GetRecordsAsync();
//transform the database records and return them
}
And call it as above.
Let's assume you are doing all of this processor intensive work as a result of a button click. Hopefully you already have the work in a separate method and are calling that method from the click event. If you actually have all of your work inside the click event, move it out into its own method and call it from the click event handler.
Now that is still on a single thread. I'll just address using a separate thread here, though you should look into tasks on your own as well. To use a separate thread for the hard work, write 2 lines of code like this:
Thread t = new Thread(nameOfTimeConsumingMethod);
t.Start();
And that will do it. If you need to write output to, say, textBox1, you cannot do so directly from the new thread (no cross thread calls). But you can still write to that box easily enough indirectly like so.
BeginInvoke(new Action(()=>textBox1.text = "Hello world!"));
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I'm almost completely virgin in threading / backgroundworkers etc.
I am trying to do this:
New window shows status of a process (label) and has an ongoing
XAML-defined animation with a storyboard (three points representing
a process in the background).
Run some background intensive code, that requires some input and
returns no output.
When finished, update the UI with a message
Repeat 2 & 3 tens of times with different operations in the background each time.
While the background BL is operating I'd like the UI not to hang, but the continuation of the execution of the next BL method should only execute after the first one has ended and the UI has been updated with the message I'd like to present.
I'd like the slimmest, simplest way to do this. using .Net 4.5, so I believe we're talking Tasks, right?
I've read dozens of Stackoverflow articles and consulted uncle google and aunt MSDN, but it's overwhelming - there are many ways to do this, and I'm a bit lost.
Thanks in advance.
Whatever you're talking about are fairly simple to do with async/await. Since you said you're new to multithreading, I recommend you to read and make yourself familiarize with it. Here is a good start and this
I assume you can implement #1 yourself and you only need guidance in implementing rest. So, I'll not be talking about it in my post.
Theoretically you need a collection with the list of work needs to be done, then start one by one after the previous one is completed.
To give some code sample
List<WorkItem> workItems = ...;//Populate it somehow
private async Task DoWorkMain()
{
foreach (var item in workItems)
{
await DoWork(item);
//WorkItem completed, Update the UI here,
//Code here runs in UI thread given that you called the method from UI
}
}
private Task DoWork(WorkItem item)
{
//Implement your logic non blocking
}
Then somewhere from the UI call
await DoWorkMain();
WorkItem is a class which holds data about the work to be done.
You need to create a thread for processing the data in the background. You can go with parameterised threads and if you want to continue the second execution only after the first is completed, set a boolean variable in the while lop of the thread or write thread synchronization.
This question already has answers here:
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
(22 answers)
Closed 9 years ago.
My problem is simply that my SQL query takes over 2 minutes to complete and I can't have my application freezing up while it tries to get all that data. I've tried multi-threading but I keep running into an error that I am pretty sure you'll recognize. My code is under that.
Cross-thread operation not valid: Control 'labelEdit1' accessed from a thread other than the thread it was created on.
private void Form_Load(object sender, EventArgs e)
{
startup = new Thread(loadInThread);
startup.Start();
}
private void loadInThread()
{
//getsDataFromSQL() is the method that takes over 2 minutes to do
//it returns a String Array if that is helpful
comboEdit1.Properties.Items.AddRange(getsDataFromSQL());
startup.Abort();
}
If there are better ways to do this then please let me know, all I need is for the application to not freeze up and the data to get loaded into the comboEdit. Also I know the SQL statements could be optimized but that's not what this question is about, so please don't suggest it,.
How are you doing the multithreading? Are you creating the thread manually? Don't do that. I would recommend going with one of the following three approaches:
async/await - http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx (.NET 4.5+ only)
The Task Parallel Library - http://msdn.microsoft.com/en-us/library/dd460717.aspx (.NET 4.0+ only)
BackgroundWorker - http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Handling the thread logic manually is of course also possible. In that case you'll probably want to look into the BeginInvoke method: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.begininvoke.aspx.
You need to use dispatcher here. This is because you cannot access controls owned by UI thread from another thread. Check this link here. I have not checked this for compilation errors but this should do the trick for you with a little modification of course.
private void loadInThread()
{
//getsDataFromSQL() is the method that takes over 2 minutes to do
//it returns a String Array if that is helpful
comboEdit1.Dispatcher.BeginInvoke((Action)(() =>
{
comboEdit1.Properties.Items.AddRange(getsDataFromSQL());
}));
startup.Abort();
}
I use a BackgroundWorker and do this:
private void loadNewAsyncToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Text = "RunWorkerAsync()";
backgroundWorkerLoading.RunWorkerAsync();
}
private void backgroundWorkerLoading_DoWork(object sender, DoWorkEventArgs e)
{
UnsafeThreadMethod("hello");
EvenUnsaferThreadMethod();
}
And now the two methods.
private void UnsafeThreadMethod(string text)
{
toolStripLabelRssFeedData.Text = text;
}
private void EvenUnsaferThreadMethod()
{
panelLoading.Visible = true;
}
I don't understand why UnsafeThreadMethod doesn't throw the following exception but EvenUnsaferThreadMethod does.
Cross-thread operation not valid: Control 'panelLoading' accessed from a thread other than the > thread it was created on.
According to the message it's because toolStripLabelRssFeedData was created on the same thread but it wasn't.
I thought that I can't call controls created by the main thread and have to use the ProgressChanged event. What's going on?
And I have a second question. What is the advantage of doing it like this when I can use ProgressChanged? What should I do?
private void EvenUnsaferThreadMethod()
{
if (panelLoading.InvokeRequired)
{
panelLoading.Invoke(new MethodInvoker(() => { EvenUnsaferThreadMethod(); }));
}
else
{
panelLoading.Visible = true;
}
}
To the first question:
the cross-thread exception is deliberately thrown in Debug mode. This means there is (conditional) code checking on InvokeRequired built into most of the GUI controls. Like the Panel.
Apparently the ToolstripLabel does not make this check. Since it does not derive from Control that could be because it is outside the scope of this safety net.
Since the standard disclaimer "Any instance members are not guaranteed to be thread safe" applies to the ToolstripLabel I would just go with the normal InvokeRequired logic when setting the Text.
For your first question, I am not entirely sure, but a review from online seems to show that sometimes this will not throw an exception, but it will not update the label. Is that the case here? Is your label being updated along with having no exception?
However, I can answer you second question right now. The ProgressChanged event is meant for exactly what it sounds like. It is supposed to be called to let the UI thread know the status of the backgroundworker so that it can update itself appropriately. The original calling thread (UI in this case) is the one that is used for the ProgressChanged, so when it updates it does not need to call Invoke. But, this should really only be done for showing the progress of a background worker.
Now, if it is not an update that you are trying to pass to the calling method, then I would suggest just passing your return data back through the RunWorkerCompleted event. This passes all of your final data back up to the original (UI) thread, so that it can update the UI without any need for an Invoke.
So, yes your call to Invoke will work, though. However, understanding what each of the other events are for can help you understand why to use one way over another. Maybe a ProgressChanged event fits better? It can also declutter your code from having unnecessary invokes.
Update to first q
I still cannot find anything about the toolstrip not needing the invoke. In fact I am finding the opposite using google searches like "toolstriplabel no cross thread exception" or "toolstriplabel invoke", etc. However, as henk mentioned, the toolstriplabel doesn't inherit from control so that might explain why no invoke is required. However, my suggestion is to assume that it will act like any other UI control and make sure it is updated on the UI thread to be safe. do not rely on quirks. Better safe than sorry, you never know if things like this might change, especially since it is logically a UI item to most..,
The advantage of your second choice is that it works :)
All UI elements are created on main UI thread and, what is more important from this question perspective, is that can be acessed only within that thread.
This is the reason why your first case fails and that is the reason your second case will work. Invoke()... will redirect required merhod call to the main UI thread.
Hope this helps.
I recognize this may be a duplicate post, but I want to make sure I ask this question clearly and get an answer based on my wording.
I have a collection of forms which inherit from a common visual element: MainVisualForm. This element provides me a way to know when the form is advancing of stepping backwards. What form comes next in the sequence is dependent on user action.
I currently have this code for one such event as I am testing:
form.OnNextForm += (f, ev) =>
{
Parameters.Vehicle = ((VehicleForm)f).SelectedVehicle;
//FormStack.Push(Parameters.Vehicle == Vehicle.SUV
// ? new KeyValuePair<Type, IFormActionBehvaior>(typeof(EntertainmentForm), null)
// : new KeyValuePair<Type, IFormActionBehvaior>(typeof(ColorForm), null));
};
This assignment is followed immediately by ShowDialog() which blocks the user until the Dialog form is closed.
The question is:
After the form closes does .NET wait for the EventHandler to complete before running the code which directly follows ShowDialog() or is the handler handled by a different thread?
Thanks very much in advance
Winforms runs in a single thread - in fact you can't even access it from a second thread without running into trouble. Unless you create a thread yourself (or a BackgroundWorker or anything else that constitutes a thread), you'll only ever have one thread.
In simple, .NET Winforms work under a single thread.
It waits for the event to complete. Events are really just method calls to methods defined somewhere else (aka delegates). After all those complete, the next bit of code after ShowDialog() will run.