BackgroundWorker, Methods - c#

So putting the standard background worker crap aside. i was looking into how i can use the background worker a little more than (Worker DoWork { add some commands for it to do })
So this is what i have come up with so far. in this scenario its doing some random WMI stuff
View/ViewModel/Model
The model is called ManagementModel
public void Start(String Args)
{
if (!Worker.IsBusy)
{
//Objectivly here you can spawn an instance of a class and perform a method.. or put the function in the background worker itself depending on what you want the thing to do
ManagementModel BackgroundManagementTask = new ManagementModel();
Worker.RunWorkerAsync(BackgroundManagementTask); //Starts the background worker.
//If you specify the class to shove into the background worker, you need to put the commands of what to do in the DoWork section.
}
}
I have a methods and whatever in the class that was spawned in the Start Method
here is the method for the DoWork
private void Workers_DoWork(object sender, DoWorkEventArgs Args)
{
//This is run on a completly seperate thread, you cannot make any changes to anything outside in this method.
//you instead pass data through the Args.ReportProgress or Args.Result
if (Worker.CancellationPending)
{
Worker.ReportProgress(100, "Cancelled By User");
return;
}
else
{
//if you passed a method here, you will need to convert Args.Arguments back to what ever you passed it in as
ManagementModel Internal = Args.Argument as ManagementModel;
//bunch of stuff in the class that already works
Internal.ComputerName = System.Environment.MachineName;
Internal.Connect();
Internal.ChangeWmiLocation("cimv2",null);
ManagementObjectCollection ResultCollection = Internal.Query("Win32_Process");
ClassProperties ResultProperties = Internal.DisplayProperties;
//now return the results to the program thread
Args.Result = ResultProperties;
//now you need to deal with the data in the WorkerCompleted Event
Worker.ReportProgress(100, "Completed");
Thread.Sleep(60); //this is required at the end of each iteration of function
}
}
So my simple questions are.
is this concept possible, can i initiate an instance of a whole class and throw it into the background worker and have the background worker perform methods and functionality inside the class
if i have to pass data back to the UI. do you think that a Struct would be the best way to go.
How would i let the ViewModel know that the Background worker is completed and update the its exposed properties for the view to update.
or am i way off base ?

Yes, the concept is possible. You can basically have a background worker do and access anything that you can do and access outside of the background worker's methods; the crucial point is that no two threads should be working with objects that haven't been explicitly laid out for that at the same time, which is why for example you should not access your UI from the background worker's working thread (the UI usually constantly being used by internal methods of the UI thread as well).
Whether you use a struct or a class is irrelevant with respect to threads; it is not the data that belongs to a given thread, but the operations. The only difference could be that when passing a struct, a copy of that struct would be created and you could keep working with your struct variable in the background worker thread - but even then, the same is true for a method that invokes callbacks within its own thread before further modifying a local struct/object, so this decision is really not related to threading.
Invoke a UI method that causes the updates to the UI once the background worker has completed its work and make sure it is called on the UI thread. The latter part can be accomplished by various means, depending on the UI toolkit the UI controls may offer a dispatcher object or something like that that allows synchronizing calls with the UI thread.

Related

How to get access to the Main Thread

Is there a way to get a reference to the Main UI thread in Windows Forms from another worker thread?
Something like this:
public void FormLoad()//we are in Main UI Thread
{
Thread backThread = new Thread(DoWork);
backThread.Start();
}
public void DoWork()
{
//get Main Thread instance
//do some work
}
UPDATE
I`m interested if there is some static property or class to get reference to main thread like Thread.CurrentThread for getting current thread.
Thread MainThread=null;//for reference
public void FormLoad()//we are in Main UI Thread
{
MainThread=Thread.CurrentThread;//main thread reference
Thread backThread = new Thread(DoWork);
backThread.Start();
}
public void DoWork()
{
//get Main Thread instance
//do some work
}
This should work!!!
Well, you can always use ParameterizedThreadStart to start a thread and send parameters to it, since it's an object, you could pass a reference to the calling thread.
Knowing the Thread instance won't help, as that doesn't allow you to do anything useful. What you presumably want is to be able to get the main thread to do something (like: update itself).
In windows forms, you should have a sync-context; simply access SynchronizationContext.Current, and should should be able to use Post or Send to pass work to the main thread.
Alternatively, if that doesn't work (the ambient sync-context is null): pass any control/form to your worker; it can then call Invoke/BeginInvoke to pass work to the main thread.
An alternative approach is to expose an event that you Invoke, have the UI listen to that event, and have the UI deal with switching back to the main thread, by calling Invoke/BeginInvoke upon itself (when handling the event).

Thread calling problems

I'm a bit of a newbie at this but I am trying to get the UI on a Reversi game to run on a different thread to the move selection part but I am having some trouble calling the thread on the button click
private void playerMoveOKButton_Click(object sender, EventArgs e)
{
ReversiT.Invoke();
}
public void ReversiT() {...}
If you're trying to create a new thread, you can do something like this:
Thread thread = new Thread(ReversiT);
thread.Start();
Invoke is used for a different purpose though. It is used to run a method on a specific thread (for instance, if you run a piece of code on a separate thread but want to make UI changes, you will want to use Invoke to make those changes on the UI thread)
I would create a BackgroundWorker to handle everything for me, setting it's DoWork event to call your move method (making sure that your move method doesn't touch the UI, or if it has to, invoking the controls on the UI thread).
I'd also set up a method to update the UI on the BackgroundWorker's RunWorkerCompleted event.
Now on your button click event above, call the BGW's RunWorkerAsync() method.
You can not invoke a method like that. You can only invoke delegates. Also, calling Invoke doesn't spawn a new thread.
You can read this tutorial about delegates, and this one about threads. Also, your question leaves much space for discussion:
What do you expect from using threads?
Have you considered different options for doing background work?
etc.
Use following
this.Invoke(ReversiT);
I think you need to think about that you are actually trying to achieve here. Running code on a separate thread in a UI is a technique used to stop the UI from hanging. However, some tasks simply have to occur on the UI thread and so can't be run from another thread.
You need to break your logic out such that you can identify which parts need to run on the UI thread (anything that interacts with a control on your UI) and thus anything that can run on a separate thread.
You would end up with code like (as an example):
private void playerMoveOKButton_Click(object sender, EventArgs e)
{
//thread is merely used as an example
//you could also use a BackgroundWorker or a task
var thread = new Thread(NonUiLogic);
thread.Start();
}
private void NonUiLogic()
{
...
//execute logic that doesn't touch UI
...
BeginInvoke(ReversiT);
}
public void ReversiT() {...}
Once you have been through that exercise you may find that there is actually very little that can happen outside of the UI thread and so you really have nothing to gain from using threads.

C# Getting to original thread to set textbox values

I've got my main form Form1 running the main bulk of my program.
I have a separate thread started to perform an algorithm.
When I run the method from the new thread, method MyAlgorithm() I get the error
InvalidOperationException with the message, "Control control name accessed from a thread other than the thread it was created on."
How do I get back to the original thread so that I can run the method to update my text boxes with the latest values?
This is the method that I want to run contained in Form1, the main class in my application.
// Reset the results values
public void ShowResults()
{
while (true)
{
loopsNum.Text = Convert.ToString(resultLoopsNum);
nodesVisitedNum.Text = Convert.ToString(resultNodesVisitedNum);
nodesResolvedNum.Text = Convert.ToString(resultNodesResolvedNum);
cpuLoopsNum.Text = Convert.ToString(resultCpuLoopsNum);
shortestPathCostNum.Text = Convert.ToString(resultShortestPathCost);
}
}
I've looked at the Invoke() methods, but I don't know how to get the original instance of my Form1 from the threaded method.
I'm invoking my thread like this...
// Set the algorithm method up in it's own thread
Thread thread = new Thread(new ThreadStart(MyAlgorithm));
// Run the algorithm
thread.Start();
How do I get back to the original thread so that I can run the method to update my text boxes with the latest values?
In Windows Forms, you'd either use Control.Invoke/BeginInvoke or use a BackgroundWorker and perform the update in the progress event handler.
In WPF you'd use Dispatcher.Invoke/BeginInvoke.
In C# 5 and .NET 4.5 you'll be able to use async methods which should make a lot of this much simpler...
I've looked at the Invoke() methods, but I don't know how to get the original instance of my Form1 from the threaded method.
If the "threaded method" is just an instance method of the Form, then you've already got the this reference. If it's not, you'll need to provide that information - ideally as an ISynchronizeInvoke to avoid a direct dependency on Windows Forms if you can express the "update" part separately. (That interface is somewhat deprecated these days, in favour of synchronization contexts, but it still works perfectly well.)
Have a look at Control.Invoke():
public void ShowResults()
{
while (true)
{
Thread.Sleep(1000); // don't spam the UI thread
if (this.InvokeRequired)
{
this.Invoke((Action)UpdateGui);
}
else
{
UpdateGui();
}
}
}
private void UpdateGui()
{
loopsNum.Text = Convert.ToString(resultLoopsNum);
nodesVisitedNum.Text = Convert.ToString(resultNodesVisitedNum);
nodesResolvedNum.Text = Convert.ToString(resultNodesResolvedNum);
cpuLoopsNum.Text = Convert.ToString(resultCpuLoopsNum);
shortestPathCostNum.Text = Convert.ToString(resultShortestPathCost);
}
You can use:
myform.Invoke(ShowResults);
There's other options here too:
Alternately use a System.Forms.Timer to call ShowResults periodically. Or another option would be not to use another thread to do the operation; do it in the GUI thread and call Application.DoEvents() from within the operation when you want to let the GUI update.
The first option is nice because it keeps you from accidentally flooding the GUI with Invoke requests, and the second option is nice because it's all on the GUI thread and allows you to have fine-grain control over when things get displayed on the GUI.

How can I update a UI progressbar or backgroundworker from code in a separate class?

Somewhat new to C# but I have a major problem with getting these things to work because if my background worker is running a long process by using a method from another class, then that class has no access to the background worker in order to update the progress.
For instance:
private void bgWorker_DoWork(object sender DoWorkEventArgs e)
{
bgArgs args = e.Argument as bgArgs;
MyClass objMyClass = new MyClass();
MyClass.MyMethod(strValue, args.Option);
//Do something based on return value of long process.
}
If I try to update bgWorker from the class "MyClass", it cannot "see" bgWorker, it doesn't exist in the context of the class, it's in the UI class because in Visual Studio, that's where you drag it from the toolbox.
The only way I've gotten it to work is to pass the whole UI form to the class, which creates other problems when trying to access that class from anywhere but the main form. From there I just update the progress bar manually via ProgressBar1.PerformStep() as it runs through the loops.
Also, I've already changed the modifier on my progress bar to internal, so it's not that the class doesn't see the progress bar.
I might be able to pass the bgworker by itself to the class through the method, but that just doesn't seem right.
I think your architecture needs revising here. The background worker is for running operations in the background, like out-of-sight-out-of-mind. While it is running, you can accept feedback from it by observing the BackgroundWorker.ProgressChanged event, which will help you increment your progress bar with PerformStep(). However, you shouldn't attempt to alter the BackgroundWorker while it is running. This gets you into Threading issues, which I'm not sure you really want :) You see, the BackgroundWorker uses a different thread to perform its operations when it runs, so changing it while running means you have to access the thread it is performing its work upon. This gets ugly. It is best to just give it a method to execute, let it run, check in on its ProgressChanged, and wait for it to finish.
Assuming I'm understanding your question correctly you probably need to make a method that can access the UI progressBar despite the source thread. The below will do just that saving you from blowing up the application when you try to set the value.
private delegate void UpdateProgressBarCallback(int barValue);
private void UpdateProgressBarHandler(int barValue)
{
if (this.progressBar1.InvokeRequired)
this.BeginInvoke(new UpdateProgressBarCallback(this.UpdateProgressBarHandler), new object[]{ barValue });
else
{
// change your bar
this.progressBar1.Value = barValue;
}
}
[see http://msdn.microsoft.com/en-us/library/ms171728%28VS.80%29.aspx ]
Then you just call UpdateProgressBar(value); (likewise, if you want this to step you can adjust the arguments/way the method operates)
Next you can go about this a few ways: You can make your background worker (since it's already in another class) event driven and then attach progress changes and update the UI; or you can pass a delegate to the thread workers as a reference so it knows where to adjust the UI.
Comment and leave me a direction to go and I'll see if I can help you (and confirm I understand the question).

C# Multi threading- Move objects between threads

i am working with a winforms control that is both a GUI element and also does some internal processing that has not been exposed to the developer. When this component is instantiated it may take between 5 and 15 seconds to become ready so what i want to do is put it on another thread and when its done bring it back to the gui thread and place it on my form. The problem is that this will (and has) cause a cross thread exception.
Normally when i work with worker threads its just with simple data objects i can push back when processing is complete and then use with controls already on the main thread but ive never needed to move an entire control in this fashion.
Does anyone know if this is possible and if so how? If not how does one deal with a problem like this where there is the potential to lock the main gui?
You don't need to lock the GUI, you just need to call invoke:
Controls in Windows Forms are bound to
a specific thread and are not thread
safe. Therefore, if you are calling a
control's method from a different
thread, you must use one of the
control's invoke methods to marshal
the call to the proper thread. This
property can be used to determine if
you must call an invoke method, which
can be useful if you do not know what
thread owns a control. ref
Here is how it looks in code:
public delegate void ComponentReadyDelegate(YourComponent component);
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
// From the other thread just initialize the component
// and call the LoadComponent method on the GUI.
component.Initialize(); // 5-15 seconds
yourForm.LoadComponent(component);
Normally calling the LoadComponent from another thread will cause a cross-thread exception, but with the above implementation the method will be invoked on the GUI thread.
InvokeRequired tells you if:
the caller must call an invoke method
when making method calls to the
control because the caller is on a
different thread than the one the
control was created on.
ref
Update:
So if I understand you correctly the control object is created on a thread other than the GUI thread, therefore even if you were able to pass it to the GUI thread you still won't be able to use it without causing a cross-thread exception. The solution would be to create the object on the GUI thread, but initialize it on a separate thread:
public partial class MyForm : Form
{
public delegate void ComponentReadyDelegate(YourComponent component);
private YourComponent _component;
public MyForm()
{
InitializeComponent();
// The componet is created on the same thread as the GUI
_component = new YourComponent();
ThreadPool.QueueUserWorkItem(o =>
{
// The initialization takes 5-10 seconds
// so just initialize the component in separate thread
_component.Initialize();
LoadComponent(_component);
});
}
public void LoadComponent(YourComponent component)
{
if (this.InvokeRequired)
{
ComponentReadyDelegate e = new ComponentReadyDelegate(LoadComponent);
this.BeginInvoke(e, new object[]{component});
}
else
{
// The component is used by a UI control
component.DoSomething();
component.GetSomething();
}
}
}
Without knowing too much about the object. To avoid cross thread exceptions, you can make the initial thread invoke a call (Even if you are calling from a thread).
Copied and pasted from one of my own applications :
private delegate void UpdateStatusBoxDel(string status);
private void UpdateStatusBox(string status)
{
listBoxStats.Items.Add(status);
listBoxStats.SelectedIndex = listBoxStats.Items.Count - 1;
labelSuccessful.Text = SuccessfulSubmits.ToString();
labelFailed.Text = FailedSubmits.ToString();
}
private void UpdateStatusBoxAsync(string status)
{
if(!areWeStopping)
this.BeginInvoke(new UpdateStatusBoxDel(UpdateStatusBox), status);
}
So essentially the threaded task will call the "Async" method. Which will then tell the main form to begininvoke (Actually async itself).
I believe there is probably a shorter way to do all of this, without the need for creating delegates and two different methods. But this way is just ingrained into me. And it's what the Microsoft books teach to you do :p
The BackgroundWorker class is designed for exactly this situation. It will manage the thread for you, and let you start the thread, as well as cancel the thread. The thread can send events back to the GUI thread for status updates, or completion. The event handlers for these status and completion events are in the main GUI thread, and can update your WinForm controls. And the WinForm doesn't get locked. It's everything you need. (And works equally well in WPF and Silverlight, too.)
The control must be created and modified from the UI thread, there's no way around that.
In order to keep the UI responsive while doing long-running initialization, keep the process on a background thread and invoke any control access. The UI should remain responsive, but if it doesn't, you can add some wait time to the background thread. This is an example, using .Net 4 parallel tools: http://www.lovethedot.net/2009/01/parallel-programming-in-net-40-and_30.html
If interaction with the specific control being initialized can't be allowed until initialization finishes, then hide or disable it until complete.

Categories

Resources