Last February, I hit a problem where I was trying to implement printing from a Lightswitch screen, and was using what has now become known as the Command Table Pattern, which allows the Lightswitch client to send a command to the server. I was encountering an error with the witty message “A new instance of the EntityObject class cannot be initialized because the ambient IDataWorkspace is not available. Please use the constructor that specifies an EntitySet” which was as clear as mud to me!
I asked about this in the Lightswitch forum, and was greatly helped by the ace Lightswitch insider Justin Anderson, who patiently explained that the problem I was facing was to do with threads, dispatchers and workspaces. This area is one of those that seems to trip up a lot of people when they start digging into Lightswitch, and is very poorly documented. The few articles I have seen are fairly difficult to understand, which only compounds the problem. Thanks to Justin’s help, I got my code working, and got a better understanding of the subject.
Well, a few weeks ago, Steve added a comment to that forum post, as he was having a very similar problem when trying to create a new entity in the Click event handler of my Pixata Static Toolbar control. As I tried to explain what the problem was, I ended up explaining threads, dispatchers and workspaces, as he had hit exactly the same lack of understanding of these that led me to make the post in the first place.
He seemed to like my explanation, so I decided to post it here, as it may help someone else. Let me say in advance that this is not a comprehensive explanation, nor is it totally accurate, because it's a complex subject and I want to try and explain it in a way you'll understand. If any Lightswitch gurus are disgusted at my explanation, please feel free to leave a comment below, or email me
Let’s deal with threads first...
In order to keep the UI responsive, Lightswitch uses two threads (think of two small men inside your PC, each one doing something different, but talking to each other to keep their work in synch). The main thread, let's call him Fred, handles getting data from the server and sending it back again. The other thread, whom we'll call Jim (because Jim is a good name) handles the UI stuff, like making sure the textboxes and comboboxes are drawn on the screen, and contain the right data.
When you do things like typing, choosing from a combobox, etc, you are talking to Jim. When you hit the Save button, this sends a message to Fred. You don't talk to Fred directly like you do to Jim, as Fred is in the background, round the back of your monitor where all the dust and dead flies collect, so when you click the Save button, what really happens is that Jim sends Fred a message saying "Here Fred, this one is for you." When Fred gets the message, he sends the data to the database for you.
The tricky bit is that there are two ways that the user tells Lightswitch what to do. One is through commands, which is how you work when you add a method to the screen (Click the "Add Data Item" button and choose "Method"). This sets up a command that just tells Jim to send a message to Fred, and have Fred do the work. However, if you capture control events, such as a button's Click event, then you are asking Jim to do the work himself, and not get Fred involved at all (he's cleaning up the dead flies while he's nothing better to do).
If that hasn't confused you, then you might have a very general (and rather flippant) idea of how threads work. When you are in a method created as a data item, you are talking to Fred, and Lightswitch creates a DataWorkspace for you. When you are in a control event handler, you are talking to Jim, and there isn't a DataWorkspace around. If you want one, you have to create one.
Aside: As my regular reader will know, I’m a huge fan of Lightswitch, but I do have one big gripe with it, and I think this is the cause of a lot of confusion to new Lightswitch programmers. In the name of good software design, Microsoft used the MVVM pattern when building Lightswitch. This is a familiar pattern to WPF and Silverlight programmers, and (like MVC and MVP before it), allows a clean separation of the business layer from the UI layer.
Now, in a normal (ie WPF or Silverlight application), the view model is in a completely separate file from the view. Thus, command methods are nowhere near control event handlers, which helps keep the separation clear in the mind of the programmer.
However, in Lightswitch, the view model code is in the same file as the screen’s code, meaning that you have methods sitting right next to each other that are actually going to be executing on different threads. I think this is a very bad idea, and seems to be the source of many problems I’ve seen in the forums.
Anyway, gripe over, back to Fred and Jim...
So, if we have two threads, how do they communicate? That’s where dispatchers come in. Dispatchers are a way of having Fred pass work to Jim and vice versa.
Certain tasks need to be done by Fred, as he works with the data. However, if you are inside a control event handler, then you are talking to Jim. So, what you need to do is ask Jim very politely if he will send a message to Fred asking him to do the work. That's where dispatchers come in.
You have two dispatchers, one that passes (ie dispatches) the work to Fred (also known as Main, as he handles the main work), and one that passes the work to Jim (known as Details). Remember, when you're writing code in a control event handler, you're talking to Jim, ie to the Details thread. For example, if you are in a control’s event handler, and you want to create a new entity (as Steve was), you need to pass the job to Fred, meaning that you need to use the Main dispatcher.
In Steve’s case, he didn't actually need a dispatcher, as he could have handled the problem a different way, but if he had, he would have needed the Main dispatcher, as he was already talking to Jim (remember the code was in a control event handler), and he wanted to pass the work to Fred. In such a case, you would do something like this...
' code for Fred to do goes here
(Note that Steve was working in Visual Basic.NET, which is why I departed from the norm and didn’t use C# above)
I hope this has helped. If it's any consolation, I think dispatchers are about the most complex bit of Lightswitch there is. Hopefully, if you read the above a few times, it might make some sense. If you run into exceptions to do with threads, chances are you need a dispatcher. There are two ways to work out which one you need to use. The first is good old trial and error! Try one, and if it doesn't work, try the other. This isn't really a good approach, as you don't really get to understand what you're doing. The second approach is to keep reading and trying to understand it until it goes in.
The easiest way to think about it, which will probably work for you in most cases, is that if you are coding in an event control handler, then if you need to dispatch, you use Dispatchers.Main().BeginInvoke. If you are in a data item method, then you will need to dispatch using Me.Details.Dispatcher.BeginInvoke.
Although the DataWorkspace side of this issue is less commonly encountered, I might as well add on a quick overview of that, as it was relevant to the forum post. In simple terms, the DataWorkspace is what you use when dealing with data in Lightswitch, and one is created for you in the view model. However, when working in the screen’s code-behind, you don't have one, which is why the error message shown at the top appears. If you need to access data from an event handler, you’ll probably need to grab your own DataWorkspace.
In my original case (which is the same as Steve’s), I was trying to create a new entity. The entities that Lightswitch creates from your database have a parameterless constructor that uses the ambient DataWorkspace, meaning the one that Lightswitch creates for you (ambient = hanging around counting dead flies, waiting for you to do something that it knows about). If you are in a view model, then this works fine, which is why you generally don’t have to worry about DataWorkspaces, as most of your code should be written in the view model.
However, sometimes you need to do this stuff in event handlers, and you don’t have an ambient DataWorkspace hanging around. In this case, you need to use another entity constructor that takes a DataWorkspace as a parameter. In my case, this meant doing this...
All this does is grab hold of a DataWorkspace explicitly, and pass it to the entity’s constructor. Once you know about this, the error message at the start of this article makes more sense, but when you first encounter it, your eyes start to glaze over, and you wonder why there are so many dead flies behind your monitor (Fred has been too busy dealing with your errors to clean them out).
I hope this has been helpful to someone! If you have any comments, or would like to hear how Fred and Jim are getting on, please click the “Comments” link below and let me know.