Message Processor

Download Samples Repository

Description

Sample shows how to read and process Mil2525C message data from XML file.

"Desktop" "Store" "Phone" Available for Desktop, Store, Phone

Sample Code

<UserControl x:Class="ArcGISRuntime.Samples.Desktop.Symbology.Specialized.MessageProcessingSample"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
			 xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
			 xmlns:special="clr-namespace:Esri.ArcGISRuntime.Symbology.Specialized;assembly=Esri.ArcGISRuntime"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
	<Grid>
		<esri:MapView x:Name="MyMapView">
			<esri:Map InitialViewpoint="-245200,6665900,-207000,6687300,3857">
				<esri:ArcGISTiledMapServiceLayer ID="Basemap" 
					ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>
				<special:MessageLayer SymbolDictionaryType="Mil2525C" />
			</esri:Map>
		</esri:MapView>

		<Border Background="White" BorderBrush="Black" BorderThickness="2" Margin="30"
                HorizontalAlignment="Right" VerticalAlignment="Top">
			<StackPanel Margin="30,20">
				<TextBlock Text="Click on the button below to run the message processor. It will read simulated messages from an XML file and display military symbols on the map  using Mil2525C Symbols."
                           FontSize="14"  Width="400" TextAlignment="Left" TextWrapping="Wrap" />
				<Button x:Name="processMessagesBtn" 
						IsEnabled="False"
						Content="Process messages"  
						Margin="12,12,12,0"
                        Click="ProcessMessagesButton_Click"/>
				<Button Name="AddSelectButton" Content="Select Messages" Click="AddSelectButton_Click" Margin="12,12,12,0"/>
				<Button Name="MultipleSelectButton" Content="Select Multiple Messages" Click="MultipleSelectButton_Click" Margin="12,12,12,0"/>
				<Button Content="Clear Selection" Click="ClearSelectButton_Click" Margin="12,12,12,0"/>
			</StackPanel>
		</Border>
	</Grid>
</UserControl>
using Esri.ArcGISRuntime.Controls;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Layers;
using Esri.ArcGISRuntime.Symbology.Specialized;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Xml.Linq;


namespace ArcGISRuntime.Samples.Desktop.Symbology.Specialized
{
	/// <summary>
	/// Sample shows how to read and process Mil2525C message data from XML file. 
	/// </summary>
	/// <title>Message Processor</title>
	/// <category>Symbology</category>
	/// <subcategory>Specialized</subcategory>
	public partial class MessageProcessingSample : UserControl
	{
		private const string DATA_PATH = @"..\..\..\samples-data\symbology\Mil2525CMessages.xml";

		private MessageLayer _messageLayer;

		public MessageProcessingSample()
		{
			InitializeComponent();

			MyMapView.ExtentChanged += MyMapView_ExtentChanged;
		}

		// Load data - enable functionality after layers are loaded.
		private async void MyMapView_ExtentChanged(object sender, EventArgs e)
		{
			try
			{
				MyMapView.ExtentChanged -= MyMapView_ExtentChanged;

				// Wait until all layers are loaded
				await MyMapView.LayersLoadedAsync();
				
				_messageLayer = MyMapView.Map.Layers.OfType<MessageLayer>().First();
				processMessagesBtn.IsEnabled = true;
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message, "Message Processing Sample");
			}
		}

		private async void ProcessMessagesButton_Click(object sender, RoutedEventArgs e)
		{
			try
			{
				await MyMapView.LayersLoadedAsync();
				// This function simulates real time message processing by processing a static set of messages from an XML document.
				/* 
				* |== Example Message ==|
				* 
				* <message>
				*      <_type>position_report</_type>
				*      <_action>update</_action>
				*      <_id>16986029-8295-48d1-aa6a-478f400a53c0</_id>
				*      <_wkid>3857</_wkid>
				*      <sic>GFGPOLKGS-----X</sic>
				*      <_control_points>-226906.99878,6679149.88998;-228500.51759,6677576.8009;-232194.67644,6675625.78198</_control_points>
				*      <uniquedesignation>DIRECTION OF ATTACK</uniquedesignation>
				* </message>
				*/

				var file = new FileInfo(DATA_PATH);

				// Load the XML document
				XDocument xmlDocument = XDocument.Load(file.FullName, LoadOptions.None);

				// Create a collection of messages
				IEnumerable<XElement> messagesXml = from n in xmlDocument.Root.Elements() 
													where n.Name == "message" 
													select n;

				// Iterate through the messages passing each to the ProcessMessage method on the MessageProcessor.
				// The MessageGroupLayer associated with this MessageProcessor will handle the creation of any 
				// GraphicsLayers and Graphic objects necessary to display the message.
				foreach (XElement messageXml in messagesXml)
				{
					Message message = new Message(from n in messageXml.Elements() select new KeyValuePair<string, string>(n.Name.ToString(), n.Value));
					_messageLayer.ProcessMessage(message);
				}

				/*
				* Alternatively you can programmatically construct the message and set the attributes.
				* e.g.
				* 
				* // Create a new message
				* Message msg = new Message();           
				* 
				* // Set the ID and other parts of the message
				* msg.Id = messageID;
				* msg.Add("_type", "position_report");
				* msg.Add("_action", "update");
				* msg.Add("_control_points", X.ToString(CultureInfo.InvariantCulture) + "," + Y.ToString(CultureInfo.InvariantCulture));
				* msg.Add("_wkid", "3857");
				* msg.Add("sic", symbolID);
				* msg.Add("uniquedesignation", "1");
				* 
				* // Process the message using the MessageProcessor within the MessageGroupLayer
				* _messageLayer.ProcessMessage(msg);
				*/
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message, "Message Processing Sample");
			}
		}

		private List<MilitaryMessage> selectedMessages = new List<MilitaryMessage>();
		
		private async void AddSelectButton_Click(object sender, System.Windows.RoutedEventArgs e)
		{
			try
			{
				await FindIntersectingGraphicsAsync(DrawShape.Point);
			}
			catch (Exception ex)
			{
				MessageBox.Show("Selection Error: " + ex.Message, "Message Processing Sample");
			}
		}

		private async void MultipleSelectButton_Click(object sender, RoutedEventArgs e)
		{
			try
			{
				await FindIntersectingGraphicsAsync(DrawShape.Envelope);
			}
			catch (Exception ex)
			{
				MessageBox.Show("Selection Error: " + ex.Message, "Message Processing Sample");
			}
		}

		// Performs a HitTest on the rendered Messages and selects the results
		private async Task FindIntersectingGraphicsAsync(DrawShape drawMode)
		{
			// Get sub layers of the MessageLayer
			var messageSubLayers = _messageLayer.ChildLayers.Cast<MessageSubLayer>();

			// Create an empty result set
			IEnumerable<Graphic> results = Enumerable.Empty<Graphic>();

			// Set the max hits to 1
			int maxHits = 1;

			// Handle the individual Message selection mode
			if (drawMode == DrawShape.Point)
			{
				// Ask the user for the point of interest
				MapPoint mapPoint = null;
				try
				{
					mapPoint = await MyMapView.Editor.RequestPointAsync();
				}
				catch (TaskCanceledException) { }

				// Check the geometry
				if (Geometry.IsNullOrEmpty(mapPoint))
					return;

				// Get the location in screen coordinates
				var screenPoint = MyMapView.LocationToScreen(mapPoint);

				// Iterate the Message sub layers and await the HitTestAsync method on each layer
				foreach (var l in messageSubLayers)
					results = results.Concat(await l.HitTestAsync(MyMapView, screenPoint, maxHits));
			}
			// Handle the multiple Message selection mode
			else
			{
				// Increase the max hits value
				maxHits = 100;

				// Ask the user for the area of interest
				Envelope envelope = null;
				try
				{
					envelope = await MyMapView.Editor.RequestShapeAsync(drawMode) as Envelope;
				}
				catch (TaskCanceledException) { }

				// Check the geometry
				if (Geometry.IsNullOrEmpty(envelope))
					return;

				// Get the screen location of the upper left
				var upperLeft = MyMapView.LocationToScreen
					(new MapPoint(envelope.XMin, envelope.YMax, envelope.SpatialReference));

				// Get the screen location of the lower right
				var lowerRight = MyMapView.LocationToScreen
					(new MapPoint(envelope.XMax, envelope.YMin, envelope.SpatialReference));

				// Create a Rect from the two corners
				var rect = new Rect(upperLeft, lowerRight);

				// Iterate the Message sub layers and await the HitTestAsync method on each layer
				foreach (var l in messageSubLayers)
					results = results.Concat(await l.HitTestAsync(MyMapView, rect, maxHits));
			}

			if (results.Count() == 0)
				return;

			// Iterate the results and modify the Action value to Select then reprocess each Message
			foreach (var graphic in results)
			{
				// Retrieve the Message representation from the MessageLayer for each Graphic returned
				MilitaryMessage message = _messageLayer.GetMessage(graphic.Attributes["_id"].ToString()) as MilitaryMessage;

				// Modify the Action to Select
				message.MessageAction = MilitaryMessageAction.Select;

				// Reprocess the Message and add to the list
				if (_messageLayer.ProcessMessage(message))
				{
					selectedMessages.Add(message);
				}
			}
		}

		private void ClearSelectButton_Click(object sender, System.Windows.RoutedEventArgs e)
		{
			try
			{
				foreach (MilitaryMessage message in selectedMessages)
				{
					message.MessageAction = MilitaryMessageAction.UnSelect;
					_messageLayer.ProcessMessage(message);
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show("Selection Error: " + ex.Message, "Message Processing Sample");
			}
		}
	}
}
Feedback on this topic?