How can I use .Equals("string") in delegate if condition? - c#

I am using BackgroundWorker, there is an if condition inside that BackgroundWorker.DoWork but its giving cross thread operation error.
I tried the below code but it say object reference not set to instance of an object. Can any one tell me how can I use Equals method inside delegate?
((bool)(scrapeType.Invoke(new Action(() => { scrapeType.Text.Equals("Scrape URLS"); }))))
scrapeType is a TextBox.

You have to make use of the Dispatcher type. Here's an example:
Dispatcher.Invoke(()=> if(txtBox.Text.Equals("abc")) doThis(); else doThat();)
You didn't mention what framework you are using, so I assumed it is WPF.

Related

How can I avoid "different thread owns it" exceptions in a library called by a WPF app? [duplicate]

This question already has answers here:
Change WPF controls from a non-main thread using Dispatcher.Invoke
(4 answers)
Closed 7 years ago.
I've come across this exception before:
The calling thread cannot access this object because a different
thread owns it.
Usually it's been caused by event handlers that have asynchronous methods. And to fix this problem, in the past, usually all I've had to do is change something like this:
myObject.CustomEvent += MyCustomEventHandler;
To something like this:
myObject.CustomEvent += (s, e) => Dispatcher.Invoke(() => MyCustomEventHandler(s, e));
And that's all well and good when all of this code lives within the same WPF application. However, my solution is split up into multiple projects, one of which is a generic "Utilities" library that has some common functions I use frequently. In this library, I have a special "Timer" class that is a wrapper for executing a given method on a regular interval.
So it's got code that looks like this:
timer.Elapsed += OnTimedEvent;
I tried to change it to this, as I was used to doing:
timer.Elapsed += (s, e) => Dispatcher.Invoke(() => OnTimedEvent(s, e));
However, that wouldn't compile. It says:
Cannot access non-static method 'Invoke' in a static context
So, I think that Dispatcher is somehow an alias for the current dispatcher inside of a WPF application, but not otherwise? (Or something like that?) So my next attempt was to change the code to this:
timer.Elapsed += (s, e) => Dispatcher.CurrentDispatcher.Invoke(() => OnTimedEvent(s, e));
That does compile, thankfully. However, it doesn't solve my problem. I'm still seeing those nasty InvalidOperationExceptions with the same message as before:
The calling thread cannot access this object because a different
thread owns it.
So I successfully accomplish nothing by adding CurrentDispatcher. I must confess that I have a bit of a knowledge gap when it comes to some of this threading stuff, so any counsel you can offer is much appreciated!
What to do depends on your library, but in most cases the right solution is to do nothing, not in the library itself.
At some point, if you are getting that exception, then some UI object is being called to handle the event. It is that UI object that should concern itself with calling Dispatcher.Invoke().
Note that Dispatcher is not an "alias". In the contexts in which you've used it before, it was a member of the object in which you were writing the code.
The static Dispatcher.CurrentDispatcher property returns the Dispatcher object for the current thread. Of course, if the code is running in a thread other than the UI thread where you want to invoke the operation, that's the wrong Dispatcher object.
But that does suggest an approach for code where your library is somehow specifically intended to deal the issue of cross-thread invocation. For examples in .NET, see classes like BackgroundWorker and Progress<T>. If you are writing a similar type, then you can capture the Dispatcher object when your class is instantiated (i.e. in the constructor). Save the value of Dispatcher.CurrentDispatcher, and use that saved object reference when you need to call Invoke().
But really, that scenario is very rare. Most of the time, one is writing library code that would otherwise have zero dependency on the UI, its thread, its Dispatcher or anything else UI related. In that much more common case, the right thing to do is not do anything in the library itself. Instead, let the client code of the library deal with it, if necessary.
Doing it that way simplifies the library, and allows it to be used in any variety of scenario, with or without a Dispatcher. And of course, when you leave the responsibility to the UI object, it has the Dispatcher property you are used to using, so you don't need to mess around with e.g. Application.Current.Dispatcher.

C# Invoke only for write access?

Do I only need to use Invoke, if the access is a write access? Is it safe to get the property of a GUI object without invoke?
new Thread(() =>
{
Invoke((MethodInvoker)(() => mbrVerticalProgressBar1.Value++));
if (TaskbarManager.IsPlatformSupported)
{
TaskbarManager.Instance.SetProgressValue(
mbrVerticalProgressBar1.Value,
mbrListOfURLsCount);
}
}).Start();
The MSDN Library makes no bones about it, it declares every method and property of the Control class thread-unsafe except InvokeRequired, BeginInvoke, Invoke and CreateGraphics.
That's not entirely accurate, there certainly are a few properties that are accidentally thread-safe because they use a backing variable. You'd have to know the actual implementation of the property getter and take a gamble on it not going to chance in the future.
And yes, ProgressBar.Value uses such a backing variable, the private value field. You can tell from the Reference Source or a decompiler. However, that's only for the getter, the setter is most certainly not. Because it needs to actually get the visible appearance of the control to change.
Btw, always favor BeginInvoke over Invoke. Invoke has pretty unpleasant characteristics, it is very apt to cause deadlock and it is very slow. You only need Invoke() when you need its return value, not the case here.
It depends upon what that write is going to do. For example you can read/write Tag property of control in any thread without any problem.
Technically anything that fires a call to Control.Handle property should be in UIThread because UIThread owns that control, so it should be accessed in that thread only, else it will end up throwing an InvalidOperationException when debugger attached.

How to use BeginInvoke C#

Could you explain this for me please:
someformobj.BeginInvoke((Action)(() =>
{
someformobj.listBox1.SelectedIndex = 0;
}));
Could you tell me how can I use begininvoke exactly?
What is Action type?
Why there is blank brackets ()?
And what does this mean =>?
Action is a Type of Delegate provided by the .NET framework. The Action points to a method with no parameters and does not return a value.
() => is lambda expression syntax. Lambda expressions are not of Type Delegate. Invoke requires Delegate so Action can be used to wrap the lambda expression and provide the expected Type to Invoke()
Invoke causes said Action to execute on the thread that created the Control's window handle. Changing threads is often necessary to avoid Exceptions. For example, if one tries to set the Rtf property on a RichTextBox when an Invoke is necessary, without first calling Invoke, then a Cross-thread operation not valid exception will be thrown. Check Control.InvokeRequired before calling Invoke.
BeginInvoke is the Asynchronous version of Invoke. Asynchronous means the thread will not block the caller as opposed to a synchronous call which is blocking.
I guess your code relates to Windows Forms.
You call BeginInvoke if you need something to be executed asynchronously in the UI thread: change control's properties in most of the cases.
Roughly speaking this is accomplished be passing the delegate to some procedure which is being periodically executed. (message loop processing and the stuff like that)
If BeginInvoke is called for Delegate type the delegate is just invoked asynchronously.
(Invoke for the sync version.)
If you want more universal code which works perfectly for WPF and WinForms you can consider Task Parallel Library and running the Task with the according context. (TaskScheduler.FromCurrentSynchronizationContext())
And to add a little to already said by others:
Lambdas can be treated either as anonymous methods or expressions.
And that is why you cannot just use var with lambdas: compiler needs a hint.
UPDATE:
this requires .Net v4.0 and higher
// This line must be called in UI thread to get correct scheduler
var scheduler = System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext();
// this can be called anywhere
var task = new System.Threading.Tasks.Task( () => someformobj.listBox1.SelectedIndex = 0);
// also can be called anywhere. Task will be scheduled for execution.
// And *IF I'm not mistaken* can be (or even will be executed synchronously)
// if this call is made from GUI thread. (to be checked)
task.Start(scheduler);
If you started the task from other thread and need to wait for its completition task.Wait() will block calling thread till the end of the task.
Read more about tasks here.

Is BeginInvoke/EndInvoke good practice for invoking on main thread?

Is it good practice to invoke delegate for MainForm thread - this way?:
Txt.MainForm.EndInvoke(
Txt.MainForm.BeginInvoke(
new MethodInvoker(delegate()
{ // code here }
)));
No - because if you're calling EndInvoke, that will block until the delegate has completed. If you want that behaviour, just use Invoke instead.
To put it another way: if you're trying to do something other than blocking until your (presumably UI-modifying) delegate has executed in the UI thread, you should explain what that something is. If there isn't anything else, then Invoke will give you simpler code.
It doesn't make a lot of sense as the code fires up an asynchronous call and then immediately waits for the call to finish. I.e. you end up waiting on the calling thread.
Not considering the thing that other mentioned (I believe this EndInvoke - BeginInvoke chain is just an example usage of delegate): Using delegates is 100% OK. If this is the only usage of the delegate body, there's no need to define it as a named method. It is cleaner in the code and there's no need to jump through the file. Consider using newer syntax for delegates:
new MethodInvoker(() => { // code here })

C# Func Delegate throws Thread Exception

So, maybe I misunderstood the usage of Func but
Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString();
Creates a Thread Error when calling getCurrentValue(cb_message_type) from my Workerthread.
Whats the best solution to get the Selected Value of the Combobox?
Many thanks,
rAyt
Edit
MSDN
"The underlying type of a lambda expression is one of the generic Func delegates. This makes it possible to pass a lambda expression as a parameter without explicitly assigning it to a delegate."
Since windows controls have thread affinity, you have 2 options:
query this data before doing your threading code, for example passing it in as the state to the worker
query it in the worker via Control.Invoke
Since the first is trivial, I'll give an example of the second using captured variables:
object value = null;
yourCombo.Invoke((MethodInvoker) delegate {value=yourCombo.SelectedValue;});
string s = value.ToString();
Here the bits inside delegate {...} happen on the UI thread, even if the code around it is on the worker thread. You can mix the above either inside your func, or call the entire func once you've switched threads.
You need to call Control.Invoke with that delegate - or make the delegate itself call it.
Using a lambda expression doesn't change the threading requirements of Windows Forms - it just makes it easier to create a delegate.
You might want to make a convenience method to do this:
// (Untested)
public static Func<TControl, TResult> WrapInvocation(Func<TControl,TResult> func)
where TControl : Control
{
return control => {
return (TResult) control.Invoke(func);
};
}
Use as:
Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString();
getCurrentValue = WrapInvocation(getCurrentValue);
Then you can call getCurrentValue(comboBox) from any thread.
The problem is that UI controls can only be used on the UI thread,
You need to call the Invoke method within the other thread, like this:
Func<ComboBox, string> getCurrentValue =
s => s.Invoke(new Func<object>(() => s.SelectedValue)).ToString();
The Invoke method takes a delegate and executes it on the UI thread.
Generally speaking, you cannot access UI controls from a thread other than that they were created on. To overcome that, you'll either have to check ISynchronizeInvoke.InvokeRequired on the control in question and branch, invoke a delegate, etc. or use a SynchronizationContext. First option is very cumbersome, whereas second one is pretty elegant:
var synchronizationContext = WindowsFormsSynchronizationContext.Current;
string currentValue = "";
synchronizationContext.Send(
() => currentValue = getCurrentValue(comboBox),
null);
If the thread will simply be reading the ComboBox, the best option if practical is probably to have an event handler on the thread which grabs the ComboBox value any time it changes, and then exposes that value via property which can be read from any thread.

Categories

Resources