I am designing a LightSwitch 2012 application to manage requests, and I want to be able to update the request state with the same reusable code across all of my screens. For example, A user can change a request state in the approval screen, the fulfillment screen, etc. Which are called by a button. Currently, I have a method in each of the .cs files where I need to update the request, using the partial void <ScreenCommand>_Execute()
methods. I am trying to change this so I can update the code from one place instead of everywhere, and I also want to not have to copy the methods to new screens that I add a button to.
Now normally I would put this in Application.cs or somewhere else with global access, but I don't have access to the same DataWorkspace
object. I also pass in the this.DataWorkspace
object from the screen, which allows access to the SaveChanges()
method. However, this seems a little smelly. Is there a better way to deal with this or a better place to put reusable commands that you want to be able to assign to buttons on multiple screens? Currently I have to be really careful about saving dirty data and I still have to wire everything up manually. I also don't know if the code runs in the proper context if it's in the Application.cs file.
To clarify, yes, I do want this to run client side, so I can trigger emails from their outlook inboxes and the like.

- 87
- 5
1 Answers
What you're trying to do is simply good programming practice, putting code that's required in more than one place in a location where it can be called from each of those places, yet maintained in just one place. It's just a matter of getting used to the way you have to do things in LightSwitch.
You can add code in a module (or a static class in C#) in the UserCode folder of the Client project. That's part of the reason the folder exists, as a place to put "user code". To do this, switch to File View, then right-click the UserCode folder to add your module/class. Add your method in the newly created module/class. You can create as many of these as you like (if you like to keep code separated), or you can add other methods to the same module/class, it's up to you.
However, I wouldn't go passing the data workspace as a parameter to the reusable method that you create. I wouldn't even pass the entity object either, just the values that you need to calculate the required state. But the actual invoking of the data workspace's SaveChanges method should remain in the screen's code. Think of the screen as a "unit of work".
In each button's Execute method (in your various screens), you call your method with values from the entity being manipulated in the screen & return the result. Assign the calculated returned value to the entity's State property (if that's what you have), then call the screen's Save method (or use the screen's Close method, passing true for the SaveChanges parameter). There's no need to call the data workspace's SaveChanges method, & you're doing things the "LightSwitch way" by doing it this way.
Another benefit of doing it this way, is that your code can now be unit tested, as it's no longer dependent on any entity.
I hope that all makes sense to you.

- 3,842
- 1
- 24
- 24
-
OK, I see what you're saying, however, I guess my main apprehension is in calling the `Application.Current.CreateDataWorkspace()` method. Is this an expensive operation? If I am checking a property on e.g. my request object (say I want to filter my requests by only the ones where the user has an appropriate permission to handle, for instance), and I call this in a where clause, will this DataWorkspace creation cause performance issues? – DTreth Mar 14 '13 at 19:39
-
Is this a new question? Nowhere in anything I explained did I mention needing to use CreateDataWorkspace, nor did you in your question. If you use the screen correctly as a unit of work, you shouldn't need CreateDataWorkspace, as each screen always already has a DataWorkspace of its own. – Yann Duran Mar 15 '13 at 00:45
-
Then maybe I should edit my question. If I move the code out I no longer have the `this.DataWorkspace` object to be able to select the correct attribut for the property. I did not mention that I was using it as: `request.RequestState = DataWorkspace.DataSource.RequestStates.Where((r) => r.StateName == newStateName).Single()` – DTreth Mar 15 '13 at 03:14
-
Well if that's the code you want to be "reusable", that's a different story. I'm not sure I'd bother, but if you really want to, then the only way is going to be to have a DataWorkspace parameter, as you originally suggested (don't use CreateDataWorkspace(), or it won't be part of the screen's unit of work). I'd also suggest using FirstOrDefault() instead of Single() (or at the very least SingleOrDefault()). If you don't use one of those two, if there's no match you'll get an exception. If you use one of those two suggestions, then you'll get a null returned for no match. – Yann Duran Mar 15 '13 at 12:12
-
I am well aware of the `Single()` versus `SingleOrDefault()` or `FirstOrDefault()`, and in each instance I try to use the one that's appropriate. In this case, the `RequestState`s are baked into the DB deployment, so that query better damn well return one and only one response. Anyway, I got the answer I was after, but should I edit my question, and you your answer, to reflect the information in our comments? – DTreth Mar 15 '13 at 14:20