Wednesday, September 26, 2012 3:21 PM
I'm trying to understand how threading works within LightSwitch and when to use it. Currently if I get and error, because somethings not called from the correct thread, I simply play around with it until it works. Without a firm understanding of what's going on, this process may make the program work but you may get strange or unexpected results.
So, my questions is, does anyone have a firm understanding how threading works within LS and when to use it?
I did read this article which was of some use but it would be great for a more detail explanation.
Wednesday, September 26, 2012 10:33 PM
The system uses Silverlight for its main presentation layer, in general all of the presentation layer would be instide it's own thread.
When working with a web deployed package you ned to break out of the UI threads to interact with the desktop, you should do the same in a desktop model just to keep it consistant..
But the Lightswitch team should be able to give you a proper answer. :)
Wednesday, September 26, 2012 11:04 PM
Currently, I just use LS for web applications.
Hopefully the Lightswitch team can explain how threading works within LS.
Thursday, September 27, 2012 6:09 AMModerator
I'll try to explain in briefly and not go into gritty detail, unless you want it.
Essentially every object you interact with through code has affinity to a particular thread in the application. You interact with every thread through the use of dispatchers, which allow you to execute a block of code on the thread that the dispatcher owns.
A LightSwitch application has several dispatchers:
- One dispatcher for the main thread (sometimes referred to as the UI thread). Any access to UI elements must be done on this dispatcher.
- One dispatcher for the LightSwitch application.
- One dispatcher for each open screen.
Whenever interacting with data, you always must access the data on the dispatcher in which data objects have affinity. If you try to do otherwise, you will cause exceptions to be thrown (the most common being an InvalidOperationException stating that an invalid cross-thread access has occurred), data won't load, or data will load but not return any meaningful results immediately. So if you want to access/interact with data on a particular screen, you must execute the code on that screen's dispatcher. You can always check if you are already on the dispatcher thread of an object by calling the CheckAccess method on the details of the object; it will return true if you are already on that dispatcher's thread (so you can synchronously access the object) or false if you are on a different dispatcher's thread.
Justin Anderson, LightSwitch Development Team
- Marked As Answer by Dave Vorgang Thursday, September 27, 2012 11:12 PM
Thursday, September 27, 2012 3:37 PM
Thanks Justin, that helps. I do think more needs to be done to explain this in more detail with examples. For example I do have the following code that seems to work:
Private Sub ExportAllStudentsClicked(sender As Object, e As System.Windows.RoutedEventArgs) ExportAllStudentsStart() End Sub Private Sub ExportAllStudentsStart() ExportAllStudentsCompleted = False Dim dialog = New SaveFileDialog() dialog.Filter = "CSV (*.csv)|*.csv" If dialog.ShowDialog() = True Then ExportAllStudentsStream = dialog.OpenFile() ExportAllStudentsStream.Flush() Me.Details.Dispatcher.BeginInvoke( Sub() Dim i As Integer = 0 Dim Recs = DataWorkspace.ShotEntryData.StudentsByFacilityId(ppvFacility.FacilityIdent).Include("Group").Include("Facility").Include("Grade") For Each a As Student In Recs.OrderBy(Function(x) x.LastName).ThenBy(Function(x) x.FirstName) If i = 0 Then ExportAllStudentsString.AppendFormat("StudentIdent" & "," & "FacilityIdent" & "," & "OverallAssessment" & System.Environment.NewLine, a) End If ExportAllStudentsString.AppendFormat(Out(a.StudentIdent.ToString) & Out(a.Facility.FacilityIdent.ToString) & Out(a.OverallAssessment, , , True) & System.Environment.NewLine, a) i = i + 1 Next ExportAllStudentsCompleted = True End Sub) End If End Sub Private Sub ExportAllStudentsCompleted_Changed() If Not ExportAllStudentsCompleted Then Exit Sub If ExportAllStudentsString.Length = 0 Then ShowMessageBox("No records have been extracted.") Else Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke( Sub() Using stream As New StreamWriter(ExportAllStudentsStream) stream.Write(ExportAllStudentsString.ToString(0, ExportAllStudentsString.Length - 1)) stream.Close() ExportAllStudentsString.Clear() End Using End Sub) ShowMessageBox("Data has been extracted.") End If ExportAllStudentsCompleted = False End Sub
The program uses Me.Details.Dispatcher.BeginInvoke to read data from the DataWorkspace and store the data in a StringBuilder variable (ExportAllStudentsString). I was first surprised that the dispatcher would allow me to access ExportAllStudentsString, but it did. Since the Dispatcher was running async I had to create some sort of trigger to let the program know when the data was all read. For that I used a screen property called ExportAllStudentsCompleted. When that property changed I then took the ExportAllStudentString and, using the Main dispatcher, was able to write the string to the file.
All this to say that this took me a while to figure out. And, I don't totally understand it or if I'm doing it right. All I know is so far it's working but I feel that maybe there are timing issues that I have not bumbed into yet.
Yes, I think it would help me and others to have some good examples on how threading works together within LS.