diff --git a/src/SampleApp.WinDesktop/AltitudeGraph.xaml b/src/SampleApp.WinDesktop/AltitudeGraph.xaml
new file mode 100644
index 0000000..d5b9d23
--- /dev/null
+++ b/src/SampleApp.WinDesktop/AltitudeGraph.xaml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SampleApp.WinDesktop/AltitudeGraph.xaml.cs b/src/SampleApp.WinDesktop/AltitudeGraph.xaml.cs
new file mode 100644
index 0000000..5d35869
--- /dev/null
+++ b/src/SampleApp.WinDesktop/AltitudeGraph.xaml.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace SampleApp.WinDesktop
+{
+ ///
+ /// Interaction logic for AltitudeGraph.xaml
+ ///
+ public partial class AltitudeGraph : UserControl
+ {
+ Queue datapoints = new Queue();
+ double min = double.MaxValue;
+ double max = double.MinValue;
+ public AltitudeGraph()
+ {
+ InitializeComponent();
+ MaxDatapoints = 150;
+ }
+
+ public void AddDataPoint(double value)
+ {
+ if (double.IsNaN(value))
+ return;
+ datapoints.Enqueue(value);
+ min = Math.Min(value, double.IsNaN(min) ? value : min);
+ max = Math.Max(value, double.IsNaN(max) ? value : max);
+ if (datapoints.Count > MaxDatapoints)
+ {
+ double val = datapoints.Dequeue();
+ //If this is the limiting value, recalculate min/max
+ if (val == min)
+ min = datapoints.Min();
+ if (val == max)
+ max = datapoints.Max();
+ }
+ UpdatePath();
+ mintb.Text = min.ToString("0");
+ maxtb.Text = max.ToString("0");
+ }
+
+ private void UpdatePath()
+ {
+ if(!datapoints.Any())
+ {
+ path.Data = null;
+ return;
+ }
+ var data = datapoints.ToArray();
+ List segments = new List();
+ for(int i=1;i
-
+
diff --git a/src/SampleApp.WinDesktop/MainWindow.xaml b/src/SampleApp.WinDesktop/MainWindow.xaml
index 7e5f61d..7611dd2 100644
--- a/src/SampleApp.WinDesktop/MainWindow.xaml
+++ b/src/SampleApp.WinDesktop/MainWindow.xaml
@@ -1,7 +1,8 @@
@@ -12,89 +13,153 @@
+ BlurRadius="20" Opacity=".5" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1200
- 2400
- 4800
- 9600
- 19200
- 38400
- 57600
- 115200
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1200
+ 2400
+ 4800
+ 9600
+ 19200
+ 38400
+ 57600
+ 115200
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SampleApp.WinDesktop/MainWindow.xaml.cs b/src/SampleApp.WinDesktop/MainWindow.xaml.cs
index 8dc0c3f..4b43eb6 100644
--- a/src/SampleApp.WinDesktop/MainWindow.xaml.cs
+++ b/src/SampleApp.WinDesktop/MainWindow.xaml.cs
@@ -1,230 +1,248 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-using NmeaParser;
-
-namespace SampleApp.WinDesktop
-{
- ///
- /// Interaction logic for MainWindow.xaml
- ///
- public partial class MainWindow : Window
- {
- private Queue messages = new Queue(101);
- private NmeaParser.NmeaDevice currentDevice;
- //Dialog for browsing to nmea log files
- private Microsoft.Win32.OpenFileDialog nmeaOpenFileDialog = new Microsoft.Win32.OpenFileDialog()
- {
- Filter = "Text files|*.txt|NMEA Log|*.nmea|All files|*.*",
- InitialDirectory = new System.IO.FileInfo(typeof(MainWindow).Assembly.Location).DirectoryName
- };
- public MainWindow()
- {
- InitializeComponent();
-
- //Get list of serial ports for device tab
- var availableSerialPorts = System.IO.Ports.SerialPort.GetPortNames().OrderBy(s=>s);
- serialPorts.ItemsSource = availableSerialPorts;
- serialPorts.SelectedIndex = 0;
- // Use serial portName:
- //var comPort = availableSerialPorts.First();
- //var portName = new System.IO.Ports.SerialPort(comPort, 4800);
- //var device = new NmeaParser.SerialPortDevice(portName);
-
- //Use a log file for playing back logged data
- var device = new NmeaParser.NmeaFileDevice("NmeaSampleData.txt");
-
- StartDevice(device);
- }
-
- ///
- /// Unloads the current device, and opens the next device
- ///
- ///
- private async void StartDevice(NmeaParser.NmeaDevice device)
- {
- //Clean up old device
- if (currentDevice != null)
- {
- currentDevice.MessageReceived -= device_MessageReceived;
- if (currentDevice.IsOpen)
- await currentDevice.CloseAsync();
- currentDevice.Dispose();
- }
- output.Text = "";
- messages.Clear();
- gprmcView.Message = null;
- gpggaView.Message = null;
- gpgsaView.Message = null;
- gpgllView.Message = null;
- pgrmeView.Message = null;
- satView.GsvMessage = null;
- //Start new device
- currentDevice = device;
- currentDevice.MessageReceived += device_MessageReceived;
- var _ = currentDevice.OpenAsync();
- if (device is NmeaParser.NmeaFileDevice)
- currentDeviceInfo.Text = string.Format("NmeaFileDevice( file={0} )", ((NmeaParser.NmeaFileDevice)device).FileName);
- else if (device is NmeaParser.SerialPortDevice)
- {
- currentDeviceInfo.Text = string.Format("SerialPortDevice( port={0}, baud={1} )",
- ((NmeaParser.SerialPortDevice)device).Port.PortName,
- ((NmeaParser.SerialPortDevice)device).Port.BaudRate);
- }
- }
-
- private void device_MessageReceived(object sender, NmeaParser.NmeaMessageReceivedEventArgs args)
- {
- Dispatcher.BeginInvoke((Action) delegate()
- {
- messages.Enqueue(args.Message.ToString());
- if (messages.Count > 100) messages.Dequeue(); //Keep message queue at 100
- output.Text = string.Join("\n", messages.ToArray());
- output.Select(output.Text.Length - 1, 0); //scroll to bottom
-
- if (args.Message is NmeaParser.Messages.Gsv gpgsv)
- {
- satView.GsvMessage = gpgsv;
- }
- else if (args.Message is NmeaParser.Messages.Rmc)
- gprmcView.Message = args.Message as NmeaParser.Messages.Rmc;
- else if (args.Message is NmeaParser.Messages.Gga)
- gpggaView.Message = args.Message as NmeaParser.Messages.Gga;
- else if (args.Message is NmeaParser.Messages.Gsa)
- gpgsaView.Message = args.Message as NmeaParser.Messages.Gsa;
- else if (args.Message is NmeaParser.Messages.Gll)
- gpgllView.Message = args.Message as NmeaParser.Messages.Gll;
- else if (args.Message is NmeaParser.Messages.Garmin.Pgrme)
- pgrmeView.Message = args.Message as NmeaParser.Messages.Garmin.Pgrme;
- else
- {
- var ctrl = MessagePanel.Children.OfType().Where(c => c.Message.MessageType == args.Message.MessageType).FirstOrDefault();
- if (ctrl == null)
- {
- ctrl = new UnknownMessageControl()
- {
- Style = this.Resources["card"] as Style
- };
- MessagePanel.Children.Add(ctrl);
- }
- ctrl.Message = args.Message;
- }
- });
- }
-
- //Browse to nmea file and create device from selected file
- private void OpenNmeaLogButton_Click(object sender, RoutedEventArgs e)
- {
- var result = nmeaOpenFileDialog.ShowDialog();
- if (result.HasValue && result.Value)
- {
- var file = nmeaOpenFileDialog.FileName;
- var device = new NmeaParser.NmeaFileDevice(file);
- StartDevice(device);
- }
- }
-
- //Creates a serial port device from the selected settings
- private void ConnectToSerialButton_Click(object sender, RoutedEventArgs e)
- {
- try
- {
- var portName = serialPorts.Text as string;
- var baudRate = int.Parse(baudRates.Text);
- var device = new NmeaParser.SerialPortDevice(new System.IO.Ports.SerialPort(portName, baudRate));
- StartDevice(device);
- }
- catch(System.Exception ex)
- {
- MessageBox.Show("Error connecting: " + ex.Message);
- }
- }
-
- //Attempts to perform an auto discovery of serial ports
- private async void AutoDiscoverButton_Click(object sender, RoutedEventArgs e)
- {
- var button = sender as Button;
- button.IsEnabled = false;
- System.IO.Ports.SerialPort port = await Task.Run(() => {
- return FindPort(
- new System.Progress((s) => { Dispatcher.BeginInvoke((Action)delegate() { autoDiscoverStatus.Text = s; }); }));
- });
- if (port != null) //we found a port
- {
- autoDiscoverStatus.Text = "";
- serialPorts.Text = port.PortName;
- baudRates.Text = port.BaudRate.ToString();
- ConnectToSerialButton_Click(sender, e);
- }
- else
- autoDiscoverStatus.Text = "No GPS port found";
- button.IsEnabled = false;
- }
-
- //Iterates all serial ports and attempts to open them at different baud rates
- //and looks for a GPS message.
- private static System.IO.Ports.SerialPort FindPort(IProgress progress = null)
- {
- var ports = System.IO.Ports.SerialPort.GetPortNames().OrderBy(s => s);
- foreach (var portName in ports)
- {
- using (var port = new System.IO.Ports.SerialPort(portName))
- {
- var defaultRate = port.BaudRate;
- List baudRatesToTest = new List(new[] { 9600, 4800, 115200, 19200, 57600, 38400, 2400 }); //Ordered by likelihood
- //Move default rate to first spot
- if (baudRatesToTest.Contains(defaultRate)) baudRatesToTest.Remove(defaultRate);
- baudRatesToTest.Insert(0, defaultRate);
- foreach (var baud in baudRatesToTest)
- {
-
- if (progress != null)
- progress.Report(string.Format("Trying {0} @ {1}baud", portName, port.BaudRate));
- port.BaudRate = baud;
- port.ReadTimeout = 2000; //this might not be long enough
- bool success = false;
- try
- {
- port.Open();
- if (!port.IsOpen)
- continue; //couldn't open port
- try
- {
- port.ReadTo("$GP");
- }
- catch (TimeoutException)
- {
- continue;
- }
- success = true;
- }
- catch
- {
- //Error reading
- }
- finally
- {
- port.Close();
- }
- if (success)
- {
- return new System.IO.Ports.SerialPort(portName, baud);
- }
- }
- }
- }
- return null;
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using Esri.ArcGISRuntime.Mapping;
+using NmeaParser;
+
+namespace SampleApp.WinDesktop
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ private Queue messages = new Queue(101);
+ private NmeaParser.NmeaDevice currentDevice;
+ //Dialog for browsing to nmea log files
+ private Microsoft.Win32.OpenFileDialog nmeaOpenFileDialog = new Microsoft.Win32.OpenFileDialog()
+ {
+ Filter = "Text files|*.txt|NMEA Log|*.nmea|All files|*.*",
+ InitialDirectory = new System.IO.FileInfo(typeof(MainWindow).Assembly.Location).DirectoryName
+ };
+ public MainWindow()
+ {
+ InitializeComponent();
+ mapView.Map = new Map(Basemap.CreateNavigationVector());
+
+ //Get list of serial ports for device tab
+ var availableSerialPorts = System.IO.Ports.SerialPort.GetPortNames().OrderBy(s=>s);
+ serialPorts.ItemsSource = availableSerialPorts;
+ serialPorts.SelectedIndex = 0;
+ // Use serial portName:
+ //var comPort = availableSerialPorts.First();
+ //var portName = new System.IO.Ports.SerialPort(comPort, 4800);
+ //var device = new NmeaParser.SerialPortDevice(portName);
+
+ //Use a log file for playing back logged data
+ var device = new NmeaParser.NmeaFileDevice("NmeaSampleData.txt");
+
+ StartDevice(device);
+ }
+
+ ///
+ /// Unloads the current device, and opens the next device
+ ///
+ ///
+ private async void StartDevice(NmeaParser.NmeaDevice device)
+ {
+ //Clean up old device
+ if (currentDevice != null)
+ {
+ currentDevice.MessageReceived -= device_MessageReceived;
+ if (currentDevice.IsOpen)
+ await currentDevice.CloseAsync();
+ currentDevice.Dispose();
+ }
+ output.Text = "";
+ messages.Clear();
+ gprmcView.Message = null;
+ gpggaView.Message = null;
+ gpgsaView.Message = null;
+ gpgllView.Message = null;
+ pgrmeView.Message = null;
+ satView.GsvMessage = null;
+ //Start new device
+ currentDevice = device;
+ currentDevice.MessageReceived += device_MessageReceived;
+ mapView.LocationDisplay.DataSource = new NmeaLocationProvider(device);
+ mapView.LocationDisplay.IsEnabled = true;
+ mapView.LocationDisplay.InitialZoomScale = 5000;
+ mapView.LocationDisplay.AutoPanMode = Esri.ArcGISRuntime.UI.LocationDisplayAutoPanMode.Navigation;
+ if (device is NmeaParser.NmeaFileDevice)
+ currentDeviceInfo.Text = string.Format("NmeaFileDevice( file={0} )", ((NmeaParser.NmeaFileDevice)device).FileName);
+ else if (device is NmeaParser.SerialPortDevice)
+ {
+ currentDeviceInfo.Text = string.Format("SerialPortDevice( port={0}, baud={1} )",
+ ((NmeaParser.SerialPortDevice)device).Port.PortName,
+ ((NmeaParser.SerialPortDevice)device).Port.BaudRate);
+ }
+ }
+
+ private void device_MessageReceived(object sender, NmeaParser.NmeaMessageReceivedEventArgs args)
+ {
+ Dispatcher.BeginInvoke((Action) delegate()
+ {
+ messages.Enqueue(args.Message.ToString());
+ if (messages.Count > 100) messages.Dequeue(); //Keep message queue at 100
+ output.Text = string.Join("\n", messages.ToArray());
+ output.Select(output.Text.Length - 1, 0); //scroll to bottom
+
+ if (args.Message is NmeaParser.Messages.Gsv gpgsv)
+ {
+ satView.GsvMessage = gpgsv;
+ }
+ else if (args.Message is NmeaParser.Messages.Rmc)
+ gprmcView.Message = args.Message as NmeaParser.Messages.Rmc;
+ else if (args.Message is NmeaParser.Messages.Gga)
+ gpggaView.Message = args.Message as NmeaParser.Messages.Gga;
+ else if (args.Message is NmeaParser.Messages.Gsa)
+ gpgsaView.Message = args.Message as NmeaParser.Messages.Gsa;
+ else if (args.Message is NmeaParser.Messages.Gll)
+ gpgllView.Message = args.Message as NmeaParser.Messages.Gll;
+ else if (args.Message is NmeaParser.Messages.Garmin.Pgrme)
+ pgrmeView.Message = args.Message as NmeaParser.Messages.Garmin.Pgrme;
+ else
+ {
+ var ctrl = MessagePanel.Children.OfType().Where(c => c.Message.MessageType == args.Message.MessageType).FirstOrDefault();
+ if (ctrl == null)
+ {
+ ctrl = new UnknownMessageControl()
+ {
+ Style = this.Resources["card"] as Style
+ };
+ MessagePanel.Children.Add(ctrl);
+ }
+ ctrl.Message = args.Message;
+ }
+ });
+ }
+
+ //Browse to nmea file and create device from selected file
+ private void OpenNmeaLogButton_Click(object sender, RoutedEventArgs e)
+ {
+ var result = nmeaOpenFileDialog.ShowDialog();
+ if (result.HasValue && result.Value)
+ {
+ var file = nmeaOpenFileDialog.FileName;
+ var device = new NmeaParser.NmeaFileDevice(file);
+ StartDevice(device);
+ }
+ }
+
+ //Creates a serial port device from the selected settings
+ private void ConnectToSerialButton_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ var portName = serialPorts.Text as string;
+ var baudRate = int.Parse(baudRates.Text);
+ var device = new NmeaParser.SerialPortDevice(new System.IO.Ports.SerialPort(portName, baudRate));
+ StartDevice(device);
+ }
+ catch(System.Exception ex)
+ {
+ MessageBox.Show("Error connecting: " + ex.Message);
+ }
+ }
+
+ //Attempts to perform an auto discovery of serial ports
+ private async void AutoDiscoverButton_Click(object sender, RoutedEventArgs e)
+ {
+ var button = sender as Button;
+ button.IsEnabled = false;
+ System.IO.Ports.SerialPort port = await Task.Run(() => {
+ return FindPort(
+ new System.Progress((s) => { Dispatcher.BeginInvoke((Action)delegate() { autoDiscoverStatus.Text = s; }); }));
+ });
+ if (port != null) //we found a port
+ {
+ autoDiscoverStatus.Text = "";
+ serialPorts.Text = port.PortName;
+ baudRates.Text = port.BaudRate.ToString();
+ ConnectToSerialButton_Click(sender, e);
+ }
+ else
+ autoDiscoverStatus.Text = "No GPS port found";
+ button.IsEnabled = false;
+ }
+
+ //Iterates all serial ports and attempts to open them at different baud rates
+ //and looks for a GPS message.
+ private static System.IO.Ports.SerialPort FindPort(IProgress progress = null)
+ {
+ var ports = System.IO.Ports.SerialPort.GetPortNames().OrderBy(s => s);
+ foreach (var portName in ports)
+ {
+ using (var port = new System.IO.Ports.SerialPort(portName))
+ {
+ var defaultRate = port.BaudRate;
+ List baudRatesToTest = new List(new[] { 9600, 4800, 115200, 19200, 57600, 38400, 2400 }); //Ordered by likelihood
+ //Move default rate to first spot
+ if (baudRatesToTest.Contains(defaultRate)) baudRatesToTest.Remove(defaultRate);
+ baudRatesToTest.Insert(0, defaultRate);
+ foreach (var baud in baudRatesToTest)
+ {
+
+ if (progress != null)
+ progress.Report(string.Format("Trying {0} @ {1}baud", portName, port.BaudRate));
+ port.BaudRate = baud;
+ port.ReadTimeout = 2000; //this might not be long enough
+ bool success = false;
+ try
+ {
+ port.Open();
+ if (!port.IsOpen)
+ continue; //couldn't open port
+ try
+ {
+ port.ReadTo("$GP");
+ }
+ catch (TimeoutException)
+ {
+ continue;
+ }
+ success = true;
+ }
+ catch
+ {
+ //Error reading
+ }
+ finally
+ {
+ port.Close();
+ }
+ if (success)
+ {
+ return new System.IO.Ports.SerialPort(portName, baud);
+ }
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ public class ReverseConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return -(double)value;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return -(double)value;
+ }
+ }
+}
diff --git a/src/SampleApp.WinDesktop/NmeaProvider.cs b/src/SampleApp.WinDesktop/NmeaProvider.cs
new file mode 100644
index 0000000..d26024c
--- /dev/null
+++ b/src/SampleApp.WinDesktop/NmeaProvider.cs
@@ -0,0 +1,100 @@
+using Esri.ArcGISRuntime.Geometry;
+using System;
+using System.Threading.Tasks;
+
+namespace SampleApp.WinDesktop
+{
+ public class NmeaLocationProvider : Esri.ArcGISRuntime.Location.LocationDataSource
+ {
+ private NmeaParser.NmeaDevice device;
+ double m_Accuracy = 0;
+ double m_altitude = double.NaN;
+ double m_speed = 0;
+ double m_course = 0;
+
+ public NmeaLocationProvider(NmeaParser.NmeaDevice device)
+ {
+ this.device = device;
+ if(device != null)
+ device.MessageReceived += device_MessageReceived;
+ }
+ void device_MessageReceived(object sender, NmeaParser.NmeaMessageReceivedEventArgs e)
+ {
+ var message = e.Message;
+ ParseMessage(message);
+ }
+
+ public void ParseMessage(NmeaParser.Messages.NmeaMessage message)
+ {
+ bool isNewFix = false;
+ bool lostFix = false;
+ double lat = 0;
+ double lon = 0;
+ if (message is NmeaParser.Messages.Garmin.Pgrme)
+ {
+ m_Accuracy = ((NmeaParser.Messages.Garmin.Pgrme)message).HorizontalError;
+ }
+ else if(message is NmeaParser.Messages.Gst)
+ {
+ Gst = ((NmeaParser.Messages.Gst)message);
+ m_Accuracy = Math.Sqrt(Gst.SigmaLatitudeError * Gst.SigmaLatitudeError + Gst.SigmaLongitudeError * Gst.SigmaLongitudeError);
+ }
+ else if(message is NmeaParser.Messages.Gga)
+ {
+ Gga = ((NmeaParser.Messages.Gga)message);
+ isNewFix = Gga.Quality != NmeaParser.Messages.Gga.FixQuality.Invalid;
+ lostFix = !isNewFix;
+ m_altitude = Gga.Altitude;
+ lat = Gga.Latitude;
+ lon = Gga.Longitude;
+ }
+ else if (message is NmeaParser.Messages.Rmc)
+ {
+ Rmc = (NmeaParser.Messages.Rmc)message;
+ if (Rmc.Active)
+ {
+ isNewFix = true;
+ m_speed = Rmc.Speed;
+ m_course = Rmc.Course;
+ lat = Rmc.Latitude;
+ lon = Rmc.Longitude;
+ }
+ else lostFix = true;
+ }
+ else if (message is NmeaParser.Messages.Gsa)
+ {
+ Gsa = (NmeaParser.Messages.Gsa)message;
+ }
+ if (isNewFix)
+ {
+ base.UpdateLocation(new Esri.ArcGISRuntime.Location.Location(new MapPoint(lon, lat, m_altitude, SpatialReferences.Wgs84), m_Accuracy, m_speed, m_course, false));
+ }
+ else if (lostFix)
+ {
+
+ }
+ }
+
+ protected override Task OnStartAsync()
+ {
+ if (device != null)
+ return this.device.OpenAsync();
+ else
+ return System.Threading.Tasks.Task.FromResult(true);
+ }
+
+ protected override Task OnStopAsync()
+ {
+ m_Accuracy = double.NaN;
+ if(this.device != null)
+ return this.device.CloseAsync();
+ else
+ return System.Threading.Tasks.Task.FromResult(true);
+ }
+
+ public NmeaParser.Messages.Gsa Gsa { get; private set; }
+ public NmeaParser.Messages.Gga Gga { get; private set; }
+ public NmeaParser.Messages.Rmc Rmc { get; private set; }
+ public NmeaParser.Messages.Gst Gst { get; private set; }
+ }
+}
diff --git a/src/SampleApp.WinDesktop/Properties/Resources.Designer.cs b/src/SampleApp.WinDesktop/Properties/Resources.Designer.cs
deleted file mode 100644
index a3ac465..0000000
--- a/src/SampleApp.WinDesktop/Properties/Resources.Designer.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-namespace SampleApp.WinDesktop.Properties {
- using System;
-
-
- ///
- /// A strongly-typed resource class, for looking up localized strings, etc.
- ///
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class Resources {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal Resources() {
- }
-
- ///
- /// Returns the cached ResourceManager instance used by this class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SampleApp.WinDesktop.Properties.Resources", typeof(Resources).Assembly);
- resourceMan = temp;
- }
- return resourceMan;
- }
- }
-
- ///
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
- }
- }
-}
diff --git a/src/SampleApp.WinDesktop/Properties/Resources.resx b/src/SampleApp.WinDesktop/Properties/Resources.resx
deleted file mode 100644
index af7dbeb..0000000
--- a/src/SampleApp.WinDesktop/Properties/Resources.resx
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
\ No newline at end of file
diff --git a/src/SampleApp.WinDesktop/Properties/Settings.Designer.cs b/src/SampleApp.WinDesktop/Properties/Settings.Designer.cs
deleted file mode 100644
index 82e7a7e..0000000
--- a/src/SampleApp.WinDesktop/Properties/Settings.Designer.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-namespace SampleApp.WinDesktop.Properties {
-
-
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
-
- private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default {
- get {
- return defaultInstance;
- }
- }
- }
-}
diff --git a/src/SampleApp.WinDesktop/Properties/Settings.settings b/src/SampleApp.WinDesktop/Properties/Settings.settings
deleted file mode 100644
index 033d7a5..0000000
--- a/src/SampleApp.WinDesktop/Properties/Settings.settings
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/SampleApp.WinDesktop/RestoreAutoPanMode.cs b/src/SampleApp.WinDesktop/RestoreAutoPanMode.cs
new file mode 100644
index 0000000..1328995
--- /dev/null
+++ b/src/SampleApp.WinDesktop/RestoreAutoPanMode.cs
@@ -0,0 +1,148 @@
+using Esri.ArcGISRuntime.UI.Controls;
+using Esri.ArcGISRuntime.Location;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+using System.ComponentModel;
+#if NETFX_CORE
+using Windows.UI.Xaml;
+#else
+using System.Windows.Threading;
+#endif
+
+
+namespace SampleApp.WinDesktop
+{
+ public class RestoreAutoPanMode
+ {
+ private class DelayTimer
+ {
+ private Action m_action;
+ DispatcherTimer m_timer;
+ public DelayTimer(Action action)
+ {
+ m_timer = new DispatcherTimer();
+ m_timer.Tick += m_timer_Tick;
+ m_action = action;
+ }
+
+
+#if NETFX_CORE
+ void m_timer_Tick(object sender, object e)
+#else
+ void m_timer_Tick(object sender, EventArgs e)
+#endif
+ {
+ m_timer.Stop();
+ if (m_action != null)
+ m_action();
+ }
+ public void Invoke(TimeSpan delay)
+ {
+ m_timer.Stop();
+ m_timer.Interval = delay;
+ m_timer.Start();
+ }
+ public void Cancel()
+ {
+ m_timer.Stop();
+ }
+ }
+
+
+ private MapView m_mapView;
+ private DelayTimer m_timer;
+
+
+ public RestoreAutoPanMode()
+ {
+ m_timer = new DelayTimer(ResetPanMode);
+ RestoreScale = double.NaN;
+ }
+
+
+ private void ResetPanMode()
+ {
+ if (m_mapView != null && m_mapView.LocationDisplay != null)
+ {
+ if (!double.IsNaN(RestoreScale))
+ m_mapView.SetViewpointScaleAsync(RestoreScale);
+ m_mapView.LocationDisplay.AutoPanMode = this.PanMode;
+ }
+ }
+
+
+ internal void AttachToMapView(MapView mv)
+ {
+ if (m_mapView != null && m_mapView != mv)
+ throw new InvalidOperationException("RestoreAutoPanMode can only be assigned to one mapview");
+ m_mapView = mv;
+ (m_mapView as INotifyPropertyChanged).PropertyChanged += m_mapView_PropertyChanged;
+ }
+
+ internal void DetachFromMapView(MapView mv)
+ {
+ (m_mapView as INotifyPropertyChanged).PropertyChanged -= m_mapView_PropertyChanged;
+ m_mapView = null;
+ }
+
+ private void m_mapView_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ //If user stopped navigating and we're not in the correct autopan mode,
+ //restore autopan after the set delay.
+ if (IsEnabled && e.PropertyName == "IsNavigating")
+ {
+ if (m_mapView.LocationDisplay != null &&
+ m_mapView.LocationDisplay.AutoPanMode != PanMode)
+ {
+ if (!m_mapView.IsNavigating)
+ m_timer.Invoke(TimeSpan.FromSeconds(DelayInSeconds));
+ else
+ m_timer.Cancel();
+ }
+ }
+ }
+
+ public bool IsEnabled { get; set; }
+
+ public double DelayInSeconds { get; set; }
+
+ public Esri.ArcGISRuntime.UI.LocationDisplayAutoPanMode PanMode { get; set; }
+
+ public double RestoreScale { get; set; }
+
+
+ public static RestoreAutoPanMode GetRestoreAutoPanSettings(DependencyObject obj)
+ {
+ return (RestoreAutoPanMode)obj.GetValue(RestoreAutoPanSettingsProperty);
+ }
+
+
+ public static void SetRestoreAutoPanSettings(DependencyObject obj, RestoreAutoPanMode value)
+ {
+ obj.SetValue(RestoreAutoPanSettingsProperty, value);
+ }
+
+
+ public static readonly DependencyProperty RestoreAutoPanSettingsProperty =
+ DependencyProperty.RegisterAttached("RestoreAutoPanSettings", typeof(RestoreAutoPanMode), typeof(RestoreAutoPanMode),
+ new PropertyMetadata(null, OnRestoreAutoPanSettingsChanged));
+
+
+ private static void OnRestoreAutoPanSettingsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (!(d is MapView))
+ throw new InvalidOperationException("This property must be attached to a mapview");
+
+
+ MapView mv = (MapView)d;
+ var oldValue = e.OldValue as RestoreAutoPanMode;
+ if (oldValue != null)
+ oldValue.DetachFromMapView(mv);
+ var newValue = e.NewValue as RestoreAutoPanMode;
+ if (newValue != null)
+ newValue.AttachToMapView(mv);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/SampleApp.WinDesktop/SampleApp.NetCore.csproj b/src/SampleApp.WinDesktop/SampleApp.NetCore.csproj
index b12b6bc..bb6195b 100644
--- a/src/SampleApp.WinDesktop/SampleApp.NetCore.csproj
+++ b/src/SampleApp.WinDesktop/SampleApp.NetCore.csproj
@@ -15,4 +15,7 @@
PreserveNewest
+
+
+
\ No newline at end of file
diff --git a/src/SampleApp.WinDesktop/SatelliteSnr.xaml b/src/SampleApp.WinDesktop/SatelliteSnr.xaml
index 011c26d..7eaf2dd 100644
--- a/src/SampleApp.WinDesktop/SatelliteSnr.xaml
+++ b/src/SampleApp.WinDesktop/SatelliteSnr.xaml
@@ -41,7 +41,7 @@
-
diff --git a/src/SampleApp.WinDesktop/SatelliteView.xaml b/src/SampleApp.WinDesktop/SatelliteView.xaml
index 66e0748..ba03bd7 100644
--- a/src/SampleApp.WinDesktop/SatelliteView.xaml
+++ b/src/SampleApp.WinDesktop/SatelliteView.xaml
@@ -68,7 +68,7 @@
-
+