I have a class using the code below. Additional I'm using another class to check the availability of my network connection. This class provides an event for that, which I'm using to start and stop a timer.
If the event gets fired, I always get an error message
The application called an interface that was marshalled for a different thread
public class ViewModel : BindableBase
{
private DispatcherTimer timerUpdate = null;
public ViewModel()
{
NetworkAvailabilty.Instance.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
timerUpdate = new DispatcherTimer();
timerUpdate.Interval = TimeSpan.FromMinutes(15);
timerUpdate.Tick += timerUpdate_Tick;
if (NetworkAvailabilty.Instance.IsNetworkAvailable)
{
timerUpdate.Start();
}
}
private void timerUpdate_Tick(object sender, object e)
{
// do something
}
public void OnNetworkAvailabilityChanged(object source, EventArgs e)
{
if (NetworkAvailabilty.Instance.IsNetworkAvailable)
{
timerUpdate.Start();
}
else
{
timerUpdate.Stop();
}
}
}
So after some research I fixed the issue using the following code:
public void OnNetworkAvailabilityChanged(object source, EventArgs e)
{
if (NetworkAvailabilty.Instance.IsNetworkAvailable)
{
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
timerUpdate.Start();
});
}
else
{
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
timerUpdate.Stop();
});
}
}
But what's behind that issue and how doeas this part of the code prevents this error message?
Even here Visual Studio tells me that I should consider to use await in front of Windows.ApplicationModel.....
But what's behind that issue
DispatcherTimer is created on the UI thread, and it is what is called a "thread-affine" object (just like most UI components). This means that it "binds" to its UI thread and now belongs to it.
NetworkAvailabilty is not a UI component, and it always raises its NetworkAvailabilityChanged event on a thread pool thread.
Thus, OnNetworkAvailabilityChanged is running on a thread pool thread, and it tries to access the DispatcherTimer which is bound to the UI thread. That's what causes the exception:
The application called an interface that was marshalled for a different thread
It's saying that DispatcherTimer is marshalled for the UI thread (and thus bound to the UI thread), but your app is invoking one of it's methods from a thread pool thread.
how doeas this part of the code prevents this error message?
RunAsync executes its delegate on the UI thread.
Personally, I prefer to use SynchronizationContext instead of Dispatcher/CoreDispatcher. If you do use the dispatcher, you should await the call and make OnNetworkAvailabilityChanged an async void event handler.
Related
As you can see, I have two classes. RfidReaderHardware generates event in thread "th", but Form running at another thread. As you can see, in form if use Invoke method of ListViewControl. So, question is how to change RfidReaderHardware to resolve encapsulation problem.
public class RfidReaderHardware : IDisposable
{
public event EventHandler<RfidReaderEventArgs> OnNewPackage;
Thread th;
//This method will be called from thread "th"
private void FireNewPackageEvent(UHFPackage package)
{
... code ...
}
... some code ...
}
and we have example code, where this event is using
public partial class PassageForm : Form
{
RfidReaderHardware RfidReader = new RfidReaderHardware(...);
private void Form1_Load(object sender, EventArgs e)
{
RfidReader.OnNewPackage += NewRfidPackage;
}
//not sure, but i think it's running in thread "th"
private void NewRfidPackage(Object o, RfidReaderEventArgs e)
{
ListViewItem item = new ListViewItem();
//from point of encapsulation view it's wrong as you know
CPackageList.Invoke(new Action(() => {CPackageList.Items.Add(item); }));
}
}
question is how to change RfidReaderHardware to resolve encapsulation problem
In fact there is no encapsulation problem. By definition, the relation between event source and subscriber is one to many, hence the source cannot "encapsulate" a logic for a specific subscriber. It's the subscriber choice how to handle the notification. One can ignore it, or handle it immediately, or like in your case handle it on the UI thread either synchronously (using Control.Invoke) or asynchronously (using Control.BeginInvoke).
Not so sure there's any real need to fix this, having the UI object itself deal with the fact that event is fired on the "wrong" thread is not a flaw. As long as you know it is in fact fired on the wrong thread, a documentation requirement.
.NET however has a general mechanism to solve this, it is used in several places inside the .NET Framework code. Your RfidReaderHardware class constructor can copy the value of SynchronizationContext.Current and store it in a field. With the implicit assumption that the object is created by code that runs on the UI thread. When you are ready to fire the event, and the copied object isn't null, you can then use its Post() or Send() method. Which automagically makes the code resume on the UI thread. Regardless of the specific UI class library that was used, works just as well in a WPF or Universal app for example.
Some sample code, it doesn't take much:
public class RfidReaderHardware {
public event EventHandler Received;
public RfidReaderHardware() {
syncContext = System.Threading.SynchronizationContext.Current;
}
protected void OnReceived(EventArgs e) {
if (syncContext == null) FireReceived(e);
else syncContext.Send((_) => FireReceived(e), null);
}
protected void FireReceived(EventArgs e) {
var handler = Received;
if (handler != null) Received(this, e);
}
private System.Threading.SynchronizationContext syncContext;
}
I’m using a separate class that instantiates different barcode objects depending on the type of machine, which raise events once a barcode is read.
So to transmit it to the form, I also raise an UNIQUE event ‘myEvent’ that all my forms listens, but inside the form I have to use this.Invoke((Action) mymethod(argument)); to be able to update the components at the user interface, as long as the handler to myEvent is executed on another thread different from that of the form.
So I have this:
My class -> barcode.readed(..) is triggered, then from its handler, I Raise myEvent, that is captured on my Form, and from the handler for myEvent on my form, I execute the this.Invoke…
I know this is a somewhat standard procedure, but I’d like to get rid of that Invoke, and instead, calling directly to the myMethod(argument); function.
I think that this is related to make my class thread safe, but I don’t know how to implement that in my case.
In fact, if I use the original manufacturer barcode.readed() event from inside the form it does not need to call the invoke, as long as this is thread safe, but I don’t know how to mimic that, and I really need to wrap all the different barcode handlers inside a different project, for my forms to use only one ‘myEvent’ that returns the desired barcode, and thus, not repeating code.
Thanks in advance,
Roger Tranchez
If you inherit your class from control (basically create a new custom control), you can handle events on the UI thread without using Invokes as the control (your barcode reader class) is part of the UI thread.
Sounds like you are using a worker thread for reading barcodes, to keep the UI responsive. And the barcode object just runs on whichever thread created it.
You can centralise event handling (to avoid repeating code) and read barcodes on a worker thread as follows:
Wrap the barcode object inside a custom object/library MyBarcodeReader that exposes MyEvent.
In the constructor for MyBarcodeReader, capture the current SynchronizationContext to a class field syncContext. This will be your UI's SynchronizationContext if your form constructs MyBarcodeReader.
When you activate MyBarcodeReader (e.g. MyBarcodeReader.Execute), create the barcode object on a worker thread.
When you need to raise MyEvent, call syncContext.Send (this will be on the worker thread), passing a delegate whose purpose is to raise MyEvent. syncContext.Send will synchronise to the UI thread (like Control.Invoke). The code below illustrates this.
public class MyBarcodeReader
{
private readonly SynchronizationContext syncContext;
// Handler for barcode object's Readed event.
private void Barcode.Readed(Object sender, Event e)
{
// Block the worker thread to synchronize with the thread associated
// with SynchronizationContext.
syncContext.Send(SyncMyEvent, (Object)e);
}
// Raises MyEvent on the thread associated with SynchronizationContext,
// usually a UI thread.
private void SyncMyEvent(Object o)
{
if (MyEvent != null)
{
MyEvent((Event)o);
}
}
// Constructor.
public MyBarcodeReader()
{
syncContext = SynchronizationContext.Current;
}
}
The approach here will block the worker thread (same as Control.Invoke) but not block the UI thread. If you have one or more forms that subscribe to MyEvent, they don't need to use Control.Invoke; they don't even need to know about the worker thread.
There are some excellent online references on SynchronizationContext, see CodeProject and MSDN magazine.
I've found a solution here: Basically it passes over the form control to the class constructor, and then, inside that class it uses the form.Invoke to fire the event from the form ui thread.
CLASS:
using System;
using System.Windows.Forms;
using System.Threading;
namespace ThreadTest
{
public class WorkerClass
{
private Thread thr;
// UI control for update
public Control UIControl { get; set; }
public delegate void StatusUpdate(DateTime dateTime, string message);
public event StatusUpdate OnStatusUpdate;
// Starts thread
public void Start()
{
thr = new Thread(new ThreadStart(MainWorker));
thr.Start();
}
// Main thread worker
public void MainWorker()
{
int i = 0;
while (true)
{
string message = string.Format("Value of i={0}", i++);
FireStatusUpdate(DateTime.Now, message);
Thread.Sleep(1000);
}
}
// Fire thread safe event
private void FireStatusUpdate(DateTime dateTime, string message)
{
// UIControl is set and OnStatusUpdate has subscriber
if (UIControl != null && OnStatusUpdate != null)
{
if (UIControl.InvokeRequired)
{
UIControl.Invoke(new StatusUpdate(FireStatusUpdate),
new object[] { dateTime, message });
return;
}
OnStatusUpdate(dateTime, message);
}
}
}
}
FORM:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
WorkerClass worker = new WorkerClass();
// add event handler
worker.OnStatusUpdate += new WorkerClass.StatusUpdate(worker_OnStatusUpdate);
// add UI control to invoke
worker.UIControl = this;
worker.Start();
}
void worker_OnStatusUpdate(DateTime dateTime, string message)
{
label1.Text = dateTime.ToLongTimeString();
label1.Text += " " + message;
}
}
In my case, I've changed the type of event, from StatusUpdate to
EventHandler<MyEventArgs>
, being MyEventArgs this class:
public class MyEventArgs : EventArgs
{
public string MyString { get; set; }
}
Thank you !
I've written a WPF WizardFramework which performs some actions in the background using some BackgroundWorker. While processing it can happen that I have to update an ObservableCollection which is bound to my UI.
For this case I've written a ThreadableObservableCollection, which provides threadsafe methods for Insert, Remove and RemoveAt. Though I'm using .NET 4.5 I was not able to get BindingOperations.EnableCollectionSynchronization working without many other invalid access exceptions. My Collection looks like:
public class ThreadableObservableCollection<T> : ObservableCollection<T>
{
private readonly Dispatcher _dispatcher;
public ThreadableObservableCollection()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
public void ThreadsafeInsert(int pos, T item, Action callback)
{
if (_dispatcher.CheckAccess())
{
Insert(pos, item);
callback();
}
else
{
_dispatcher.Invoke(() =>
{
Insert(pos, item);
callback();
});
}
}
[..]
}
This is working as expected, while I am using the wizard in my application. Now I'm using NUnit to write some integrationtests for the application.
There's a listener which waits for the WizardViewModel to finish it's work and looking for some pages which are injected in the Steps-Collection. After the asyncrone work is done I can use Validate to check the viewmodel state.
Unfortunately I'm using a ManualResetEvent to wait for the wizard to close. This looks like following:
public class WizardValidator : IValidator, IDisposable
{
private WizardViewModel _dialog;
private readonly ManualResetEvent _dialogClosed = new ManualResetEvent(false);
[..]
public void ListenTo(WizardViewModel dialog)
{
_dialog = dialog;
dialog.RequestClose += (sender, args) => _dialogClosed.Set();
dialog.StepsDefaultView.CurrentChanged += StepsDefaultViewOnCurrentChanged;
_dialogClosed.WaitOne();
}
[..]
}
Now there's a problem:
While the Application is running the UI Thread is not blocked, the Collection can be updated without any problems. But in my testcases the "main" Thread where I initialize the ViewModel (and because of that the Collections) is an AppDomainThread which is blocked by the testcode. Now my ThreadsafeInsert wants to update the collection but cannot use the AppDomain Thread.
But I have to wait for the wizard to finish, how can I solve this kind of deadlock? Or is there a more elegant solution for this one?
edit:
I worked around this problem with a check if there's a user interface, and only then I invoke on the Application-Thread, otherwise I change the collection intentionally on another thread. This does not prevent the exception, but it is not recognized from the test... the items are inserted nevertheless, only the NotifyCollectionChanged-Handler is not called (which is only used in the UI anyway).
if (Application.Current != null)
{
Application.Current.Dispatcher.Invoke(() =>
{
Steps.Insert(pos, step);
stepsView.MoveCurrentTo(step);
});
}
else
{
new Action(() => Steps.Insert(pos, step)).BeginInvoke(ar => stepsView.MoveCurrentToPosition(pos), null);
}
This is an ugly workaround and I am still interested in a clean solution.
Is there a way to use an alternate Dispatcher to create (e.g.) the whole ViewModel and use this to change my collection?
As I see the main problem that main thread is blocked and other operations are trying to be executed in main thread too? What about not to block main thread, like this:
// helper functions
public void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
public object ExitFrame(object f)
{
((DispatcherFrame)f).Continue = false;
return null;
}
// in your code:
while(!_dialogClosed.WaitOne(200))
DoEvents();
If it will not help then I guess need to try some SynchronisationContext workarounds.
I think the problems boil down to the fact that you create ObservableCollection that is tied to Dispatcher object.
Involving Dispatcher object directly is almost never good idea(as you just witnessed). Instead I would suggest you to see how others have implemented ThreadSafeObservableCollection. This is a little example I put together, it should illustrate the point:
public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
{
private readonly object _lock = new object();
public ThreadSafeObservableCollection()
{
BindingOperations.CollectionRegistering += CollectionRegistering;
}
protected override void InsertItem(int index, T item)
{
lock (_lock)
{
base.InsertItem(index, item);
}
}
private void CollectionRegistering(object sender, CollectionRegisteringEventArgs e)
{
if (e.Collection == this)
BindingOperations.EnableCollectionSynchronization(this, _lock);
}
}
I came across a situation which puzzled me at work today which I have simplified in the following code. This code builds and throws no exceptions during debug.
Suppose I have a WinForms app. In my main UI thread I spin off another thread which instantiates an object which in turn holds reference to a control (label1 in my example). I then call a method on my object (SetLabelText) which passes it's execution back onto the UI thread if required.
What stumped me was how, when we are back in the UI thread and executing SetLabelText, is .net CLR able to access the labelText variable when we are executing on a thread (ie the UI thread) which did not create the instance of Thing.
public partial class Form1 : Form
{
delegate void DoSomethingDelegate();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var t = new Thread(DoSomethingWithThing);
t.Start();
}
private void DoSomethingWithThing()
{
var thing = new Thing(this.label1);
thing.SetLabelText();
}
}
public class Thing
{
private Label label;
private string labelText = "new value";
delegate void SetLabelTextDelegate();
public Thing(Label label)
{
this.label = label;
}
public void SetLabelText()
{
if (this.label.InvokeRequired)
{
var setLabelDel = new SetLabelTextDelegate(SetLabelText);
this.label.Invoke(setLabelDel);
}
else
{
this.label.Text = this.labelText;
}
}
}
References to objects are available on any thread.
Threads are not sand-boxed from each other. They share resources unless you explicitly create non-shared resources.
Threads are execution contexts. Think of your application as a kitchen and each thread as a chef. They can work at the same time but if two of them try to use the same knife at the same time, things get messy. This is why c# has the lock keyword and other synchronization mechanisms.
WinForms has restrictions on access to controls because of the way WinForms renders.
I have to make a Instant Messenger server in C#. The server is a ConsoleApplication project. And I want to make a server that runs in 3 threads. I will explain in the code below.
The question is how can I invoke a function from a separate thread, or make an event on a separate thread?
This is the main server class.
public class GiNetServer
{
public void Start()
{
netServer = new NetServer();
msgHandler = new NetMsgHandler();
netServer.NewNetMsg += msgHandler.HandleMsg;
Work();
}
private void Work()
{
while(true) //This runs in the MainThread
sleep(1);
}
}
The NetServer class creates 2 Threads: acceptClientsThread and receiveMessagesThread.
The receive thread calls the NewNetMsg.
public class NetServer
{
public event NewNetMsgEventHandler NewNetMsg;
public NetServer()
{
acceptClientsThread = new Thread(ListenForClients);
receiveMessageThread = new Thread(Receive);
//and of course starts them here...
}
private void Receive()
{
while(true)
{
Heartbeat();
}
}
private void Heartbeat()
{
foreach(netClient in clientsList)
{
if (netClient.DataAvalible)
{
netClient.Recive();
}
if (!netClient.IsBufferEmpty())
{
nextMsg = netClient.NextMessage();
if (nextMsg != null)
NewNetMsg(netClient, nextMsg); //Call the event!
}
}
}
}
How can I make the msgHandler.HandleMsg function run in a separate thread or in the MainThread?
Like this, HandleMsg runs in the receiveMessagesThread.
The code above is pseudocode-ish. If there is anything ambigous please let me know.
There are a lot of different ways to move the HandleMsg call onto a different thread, depending on what your requirements are. The simplest way would be to raise the NewNetMsg event on a different thread using the ThreadPool:
ThreadPool.QueueUserWorkItem(s => NewNetMsg(netClient, nextMsg));
You could also use the Task Parallel Library (TPL). You could also add the event to a ConcurrentQueue that is processed by a dedicated background thread. And there are more options. Without more details it is impossible to give a more specific recommendation.