As our processors get stronger and stronger with multi cores, software steps up to fully utilize these cores in order to be more effective at processing. Thus born the multi threading concept where a software can spawn threads do extra work independently from the parent process.
Although ArcGIS for Desktop up until now, (10.2.2) is not fully Multi-threaded, i.e. not all its functionalities are delegated to threads for execution, you still can write your own full Multi-threaded customizations on top of it.
There is a catch though.
For instance, below is an ArcMap customization code with two command buttons, both draw marker element on the map. However, one does it with threading, the other without threading.
There is however, something interesting. The threading code I just gave you? it doesn't work. Yes its broken. The reason is that ArcGIS and ArcObjects (especfiically ICommand interface the command button for ArcMap) do not support invoking threads that owns its controls. So you will call a new thread (which is isolated from ArcMap) and then that thread will tries to draws an element on ArcMap, which she (i don't know why I think its a woman) doesn't have access to throwing an error in the process. So this is a classic problem called cross-thread violation.
Solving this problem is easy, you need to force the class that implements ICommand to have an invoke capability, so you have to make your ArcMap button into a Windows Form which allows invoking into the same thread. At least this is how I solved it, if you guys have another method please do share. Below is the code
One more thing, our command is not exactly a form until you create a handle for it. So we have to add this line in the new constructor. Showing and hiding the form will take care of this.
'force to create handle (VERY IMPORTANT)
Me.Show()
Me.Hide()
You can download source working code here
Although ArcGIS for Desktop up until now, (10.2.2) is not fully Multi-threaded, i.e. not all its functionalities are delegated to threads for execution, you still can write your own full Multi-threaded customizations on top of it.
There is a catch though.
For instance, below is an ArcMap customization code with two command buttons, both draw marker element on the map. However, one does it with threading, the other without threading.
'--------------------- Threading Example --------------------- Public Overrides Sub OnClick() 'TODO: Add CreateCircleThreading.OnClick implementation Dim pThread As New Threading.Thread(Sub() DrawCircle(RGB(255, 0, 0))) pThread.Start() End Sub '--------------------- No Threading Example --------------------- Public Overrides Sub OnClick() 'TODO: Add CreateCircleNoThreading.OnClick implementation 'draw a red circle in the center DrawCircle(RGB(0, 0, 255)) End Sub Public Sub DrawCircle(lRGBColor As Long) Dim pMxdoc As IMxDocument = m_application.Document Dim pMarkerElement As IMarkerElement = New MarkerElement Dim pMarkerSymbol As IMarkerSymbol = New SimpleMarkerSymbol Dim pColor As IColor = New RgbColor() pColor.RGB = lRGBColor pMarkerSymbol.Color = pColor pMarkerSymbol.Size = 50 pMarkerElement.Symbol = pMarkerSymbol Dim pElement As IElement = pMarkerElement pElement.Geometry = pMxdoc.ActiveView.Extent.UpperRight pMxdoc.ActiveView.GraphicsContainer.AddElement(pElement, 0) pMxdoc.ActiveView.Extent.Expand(100, 100, False) pMxdoc.ActiveView.Refresh() End SubObviously both will give you the same result, however, the threading option is better if you want to free up your cpu to do more important things, and of course if your operation is much more heavier than drawing a simple element. You want to through the bulk work on a thread to do that.
There is however, something interesting. The threading code I just gave you? it doesn't work. Yes its broken. The reason is that ArcGIS and ArcObjects (especfiically ICommand interface the command button for ArcMap) do not support invoking threads that owns its controls. So you will call a new thread (which is isolated from ArcMap) and then that thread will tries to draws an element on ArcMap, which she (i don't know why I think its a woman) doesn't have access to throwing an error in the process. So this is a classic problem called cross-thread violation.
Solving this problem is easy, you need to force the class that implements ICommand to have an invoke capability, so you have to make your ArcMap button into a Windows Form which allows invoking into the same thread. At least this is how I solved it, if you guys have another method please do share. Below is the code
Public NotInheritable Class CreateCircleThreading Inherits Form Implements ICommand ... ... Public Sub OnCommandClick() Implements ICommand.OnClick 'TODO: Add CreateCircleThreading.OnClick implementation Me.Invoke(Sub() DrawCircle(RGB(255, 0, 0))) 'Dim pThread As New Threading.Thread(Sub() DrawCircle(RGB(255, 0, 0))) 'pThread.Start() End Sub Public Sub DrawCircle(lRGBColor As Long) Dim pMxdoc As IMxDocument = m_application.Document Dim pMarkerElement As IMarkerElement = New MarkerElement Dim pMarkerSymbol As IMarkerSymbol = New SimpleMarkerSymbol Dim pColor As IColor = New RgbColor() pColor.RGB = lRGBColor pMarkerSymbol.Color = pColor pMarkerSymbol.Size = 50 pMarkerElement.Symbol = pMarkerSymbol Dim pElement As IElement = pMarkerElement pElement.Geometry = pMxdoc.ActiveView.Extent.UpperRight pMxdoc.ActiveView.GraphicsContainer.AddElement(pElement, 0) pMxdoc.ActiveView.Extent.Expand(100, 100, True) pMxdoc.ActiveView.Refresh() End Sub
One more thing, our command is not exactly a form until you create a handle for it. So we have to add this line in the new constructor. Showing and hiding the form will take care of this.
'force to create handle (VERY IMPORTANT)
Me.Show()
Me.Hide()
You can download source working code here
No comments:
Post a Comment
Share your thoughts
Note: Only a member of this blog may post a comment.