Multithreading with ArcGIS Map running on its own thread

158
4
Jump to solution
08-26-2020 02:38 PM
DanSepeda
New Contributor II

I'm new to ArcGIS SDK and using C# in general so please bare with me. I'm currently creating a .Net Application in C# that will display a GPS location of a robotic-vehicle in real time while also displaying other data from the vehicle e.g. engine speed, spray pressure, vehicle speed etc. The displaying of the vehicles location within the ArcGIS esri map works great and doesn't freeze that U.I. at all. I created two different threads, each with a socket, exclusively for receiving or sending data. The GPS position of the robotic-vehicle comes in through the receiving socket at ~ 20hz. However, when I send data to be displayed in an odometer that I made or even a simple text box then the U.I. completely freezes until the operation is complete or just shuts down.

I have tried to create the operation of changing the text box/odometer in it's own thread and calling Thread.Sleep() within that function, but it has the same outcome where it doesn't show the incremental changes in the display, but rather the result after the entire operation is completed or shutdown completely.

My MainWindow.xaml.cs looks something like the following:

namespace ArcGISRuntime.WPF.Samples.SketchOnMap 

{

private GraphicsOverlay _sketchOverlay;

public SketchOnMap()
{
InitializeComponent();

// Call a function to set up the map and sketch editor
Initialize();


}

private void Initialize()
{
// Create a light gray canvas map
Map myMap = new Map(Basemap.CreateImageryWithLabelsVector());

// Create central point where map is centered
MapPoint centralPoint = new MapPoint(X, Y, SpatialReferences.Wgs84);

// Create starting viewpoint
Viewpoint startingViewpoint = new Viewpoint(
centralPoint,
3000);
// Set starting viewpoint
myMap.InitialViewpoint = startingViewpoint;


// Create graphics overlay to display sketch geometry
_sketchOverlay = new GraphicsOverlay();
MyMapView.GraphicsOverlays.Add(_sketchOverlay);

// Assign the map to the MapView
MyMapView.Map = myMap;

// Fill the combo box with choices for the sketch modes (shapes)
SketchModeComboBox.ItemsSource = System.Enum.GetValues(typeof(SketchCreationMode));
SketchModeComboBox.SelectedIndex = 0;

// Set the sketch editor as the page's data context
DataContext = MyMapView.SketchEditor;


}

private void Update(){

   for (int i = 0; i < 8000; i++){

         textbox.Text = i.ToString();

      Thread.Sleep(1000);

}

}

 private async void DrawButtonClick(object sender, RoutedEventArgs e){}....

private void ButtonSock_Click(Object sender, RoutedEventArgs e){

Thread th1 = new Thread(Update);

th1.Start();

}

}

}

Please let me know if you have any suggestions for this. To reiterate, I can continually display the robotic-vehicles location without freezing since I have a method within the same public partial class SketchOnMap that uses the following:

private void Draw_Position(byte[] b_lat, byte[] b_lon){

double d_lat = ConvertByteArrayToDouble(b_lat);
double d_lon = ConvertByteArrayToDouble(b_lon);


MapPoint startingPoint = new MapPoint(d_lon, d_lat, SpatialReferences.Wgs84);

// Create a symbol to symbolize the point
SimpleMarkerSymbol symbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Color.Black, 10);

// Create the graphic
Graphic symbolGraphic = new Graphic(startingPoint, symbol);


_sketchOverlay.Graphics.Add(symbolGraphic);

}

Reply
0 Kudos
1 Solution

Accepted Solutions
MortenNielsen
Esri Frequent Contributor

You can't update the UI from a background thread. You'll need to use the Dispatcher to switch back to the UI Thread to update the UI:   textbox.Text = i.ToString();

Example:

Dispatcher.BeginInvoke(() =>
{
textbox.Text = i.ToString();
});

Generally I don't recommend using new Thread(). Instead use Task.Run instead, and to sleep use 'await Task.Delay(milliseconds);' to avoid holding up the thread completely.

View solution in original post

4 Replies
MichaelBranscomb
Esri Frequent Contributor

Hi,

The issue is most likely caused by the synchronous coding pattern you've used with void methods and blocking Thread.Sleep calls. Instead I recommend taking a look at some articles on asynchronous programming e.g. Asynchronous programming in C# | Microsoft Docs.

Thanks

Mike

DanSepeda
New Contributor II

Hi Michael, thanks for the article I'll take a look through it. As Morten, suggested I needed to create a Dispatcher to switch back to the UI thread- which worked great. I definitely need to read more up on multi threading. Thanks!

Reply
0 Kudos
MortenNielsen
Esri Frequent Contributor

You can't update the UI from a background thread. You'll need to use the Dispatcher to switch back to the UI Thread to update the UI:   textbox.Text = i.ToString();

Example:

Dispatcher.BeginInvoke(() =>
{
textbox.Text = i.ToString();
});

Generally I don't recommend using new Thread(). Instead use Task.Run instead, and to sleep use 'await Task.Delay(milliseconds);' to avoid holding up the thread completely.

View solution in original post

DanSepeda
New Contributor II

Hi Morten, Thanks for your help. You are spot. I wasn't able to update the UI from background thread so instead I used exactly what you said. I created a delegate object and then called the Dispatcher to switch back to the UI which worked perfectly.  Thanks again for your help.

Reply
0 Kudos