Track Editor: Difference between revisions
(→) |
(→) |
||
Line 997: | Line 997: | ||
==== Track filtering by tag fields ==== | ==== Track filtering by tag fields ==== | ||
Now that we can display | |||
==== Auto refresh track info ==== | ==== Auto refresh track info ==== |
Revision as of 12:41, 21 October 2019
This section describes how to create a WPF application interacting with a Maria Track Service, without using MariaUserControl and track layer.
General
- Note
-
- For general description of track related info, see General track service information.
- For this part you will need to include the TPG.Maria.TrackLayer NuGet package as a minimum.
- You also need to have a Track Service available.
- Sample code for this section is the MariaTrackEditor project, in the Sample Projects solution.
Start with creating a WPF App project!
- Add a view model class, e.g. TrackEditorViewModel - inheriting ViewModelBase
- Set the view model class to be the DataContext for your application.
Track service engine
The Track service engine encapsulates service interaction.
Available functions:
- Connection
-
- ConnectToTrackService
- Connect to specified track service.
- If URI is not given, endpoint info from configuration file will be used (if available).
- Binding type is assumed to be BasicHttp!
- For service configuration, see Basic map client, Service configuration
- Disconnect
- Disconnect from service
- IsConnected
- Get current connection status.
- Track lists
-
- GetTrackLists
- Retreive available tracklists from track service.
- AddTrackList
- Create a new track list.
- RemoveTrackList
- Remove track list, and all track info, if any.
- Tracks
-
- GetAllTracks
- Retreive available tracks from a specific track list, matching the search criteria.
- GetTrackData
- Retreive specified tracks from a specific track list.
- AddOrUpdateTrack
- Create or update specific track.
- Track history setting
-
- GetTrackHistoryOptions
- SetDefaultTrackHistoryOptions
- Set default track history options for new track lists.
- SetTrackHistoryOptions
- Retreive track history options for specified track list.
- Track history
-
- RemoveTrack
- Remove specified track from specific track list
- GetTrackHistory
- Retreive available track history information for specified track & track list, according to filter criteria.
Source code for MariaTrackServiceEngine
Track editor
Connection management
Connection features:
- Connect to track service
- Default track service from configuration
- Alternative track service
- Disconnect from service
- Show connection status
At startup, the Track Editor should try to connect to the latest track service successfully connected to.
To store the last value used, add a string value, StrLastUri to the project settings.
Add the following to your window xaml:
<GroupBox Header="Connection" >
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Content="Service URI"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="2"
Text="{Binding ConnectionUri}"/>
<Button Grid.Row="0" Grid.Column="3" Height="22" Margin="2"
Content="Connect"
Command="{Binding ConnectCmd}" />
<Label Grid.Row="1" Grid.Column="0" Margin="2"
Content="Status"/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="2"
VerticalAlignment="Center"
Text="{Binding ConnectionStatus}"/>
<Button Grid.Row="1" Grid.Column="3" Height="22" Margin="2"
Content="Disconnect"
Command="{Binding DisconnectCmd}"/>
</Grid>
</GroupBox>
Then, add the following to your view model:
. . .
public ICommand ConnectCmd { get { return new DelegateCommand(Connect, CanConnect); } }
public ICommand DisconnectCmd { get { return new DelegateCommand(Disconnect, CanDisconnect); } }
. . .
private void Connect(object obj = null)
{
ConnectionStatus = "Connection requested ... ";
if (_trackServiceEngine.ConnectToTrackService(ref _connectionUri))
{
Settings.Default.StrLastUri = ConnectionUri;
Settings.Default.Save();
ConnectionStatus = "Connected!";
}
else
{
ConnectionStatus = "Not connected, connection failed! ";
if (string.IsNullOrWhiteSpace(ConnectionUri))
{
ConnectionStatus += "\nSupply URI - or correct 'system.serviceModel' configuration!";
}
}
RefreshConnectionInfo();
}
private bool CanConnect(object obj)
{
return !_trackServiceEngine.IsConnected();
}
private void Disconnect(object obj)
{
_trackServiceEngine.Disconnect();
ConnectionStatus = "Disconnected!";
}
private bool CanDisconnect(object obj)
{
return _trackServiceEngine.IsConnected();
}
. . .
public string ConnectionUri {
get { return _connectionUri; }
set
{
_connectionUri = value;
NotifyPropertyChanged(() => ConnectionUri);
}
}
public string ConnectionStatus
{
get { return _connectionStatus; }
set
{
_connectionStatus = value;
NotifyPropertyChanged(() => ConnectionStatus);
}
}
. . .
internal void RefreshConnectionInfo()
{
NotifyPropertyChanged(() => ConnectionStatus);
NotifyPropertyChanged(() => ConnectionUri);
}
. . .
Track list management
Track list features:
- Display existing track lists
- Filtered view
- Add new track list
- Select track list
- Remove selected track list
Add the following to your window xaml:
<GroupBox Header="Track lists" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Margin="2"
Content="New list"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="2"
Text="{Binding NewTrackList}"
TextChanged="NewTrackListChanged"/>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="2"
Content="Filter" VerticalAlignment="Center"
IsChecked="{Binding ActiveFilter}" />
<TextBox Grid.Row="1" Grid.Column="1" Margin="2"
Text="{Binding TrackListFilter}"
VerticalAlignment="Center"
TextChanged="FilterChanged" />
<StackPanel Grid.Row="2" Grid.Column="0" >
<Label Margin="2"
Content="Track lists"/>
<StackPanel Orientation="Horizontal" Margin="2">
<Label Content="#"/>
<Label Content="{Binding TrackLists.Count}"/>
</StackPanel>
</StackPanel>
<ListBox Grid.Row="2" Grid.Column="1" Margin="2"
VerticalAlignment="Top"
ItemsSource="{Binding TrackLists}"
SelectedItem="{Binding SelectedTrackList}"/>
<Button Grid.Row="0" Grid.Column="3" Height="22" Margin="2"
Content="Add"
Command="{Binding AddTrackListCmd}"/>
<Button Grid.Row="2" Grid.Column="3" Height="22" Margin="2"
VerticalAlignment="Top"
Content="Remove"
Command="{Binding RemoveTrackListCmd}"/>
</Grid>
</GroupBox >
Then, add the following to your view model:
. . .
public ICommand AddTrackListCmd { get { return new DelegateCommand(AddTrackList, CanAddTrackList); } }
public ICommand RemoveTrackListCmd { get { return new DelegateCommand(RemoveTrackList, CanRemoveTrackList); } }
. . .
private void AddTrackList(object obj)
{
_trackServiceEngine.AddTrackList(NewTrackList) ;
ActiveFilter = false;
SelectedTrackList = NewTrackList;
RefreshTrackListDisplay();
}
private bool CanAddTrackList(object obj)
{
return !string.IsNullOrWhiteSpace(NewTrackList) && TrackLists != null && !TrackLists.Contains(NewTrackList);
}
private void RemoveTrackList(object obj)
{
_trackServiceEngine.RemoveTrackList(SelectedTrackList);
RefreshTrackListDisplay();
}
private bool CanRemoveTrackList(object obj)
{
return SelectedTrackList != null;
}
. . .
public string NewTrackList
{
get { return _newTrackList; }
set
{
_newTrackList = value;
NotifyPropertyChanged(() => NewTrackList);
}
}
public string TrackListFilter
{
get { return _trackListFilter; }
set
{
_trackListFilter = value;
NotifyPropertyChanged(() => TrackListFilter);
}
}
public bool ActiveFilter
{
get { return _activeFilter; }
set
{
_activeFilter = value;
RefreshTrackListDisplay();
}
}
public string SelectedTrackList
{
get { return _selectedTrackList; }
set
{
_selectedTrackList = value;
NotifyPropertyChanged(() => SelectedTrackList);
RefreshTrackDisplay();
}
}
public List<string> TrackLists { get { return _trackServiceEngine.GetTrackLists(ActiveFilter, TrackListFilter); } }
. . .
internal void RefreshTrackListDisplay()
{
NotifyPropertyChanged(() => NewTrackList);
NotifyPropertyChanged(() => ActiveFilter);
NotifyPropertyChanged(() => TrackListFilter);
NotifyPropertyChanged(() => SelectedTrackList);
NotifyPropertyChanged(() => TrackLists);
}
. . .
To handle the text changed events for the text boxes, add the following event handlers to the windows "Code behind"
TrackEditorViewModel _vm;
public MainWindow()
{
InitializeComponent();
_vm =new TrackEditorViewModel();
DataContext = _vm;
}
private void NewTrackListChanged(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
_vm.NewTrackList = textbox.Text;
_vm.RefreshTrackListDisplay();
}
}
private void FilterChanged(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
_vm.TrackListFilter = textbox.Text;
_vm.RefreshTrackListDisplay();
}
}
To prevent old information in the view after disconnect, add refresh of the track list display when disconnecting.
. . .
private void Disconnect(object obj)
{
_trackServiceEngine.Disconnect();
ConnectionStatus = "Disconnected!";
RefreshTrackListDisplay();
}
. . .
Track info management
Track display
- Display existing tracks in the selected list
- Filtered view
- Add new track
- Select track
- Remove selected track
Add the following to your window xaml:
. . .
<GroupBox Header="Tracks" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Margin="2"
Content="New track"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="2" Height="22"
Text="{Binding NewTrack}"
TextChanged="NewTrackChanged"/>
<CheckBox Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"
Content="Id filter"
IsChecked="{Binding ActiveTrackIdFilter}"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="2" Height="22"
VerticalAlignment="Center"
Text="{Binding TrackIdFilter}"
TextChanged="TrackIdFilterChanged" />
<StackPanel Grid.Row="3" Grid.Column="0" >
<Label Margin="2"
Content="Tracks"/>
<StackPanel Orientation="Horizontal" Margin="2">
<Label Content="#"/>
<Label Content="{Binding Tracks.Count}"/>
</StackPanel>
</StackPanel>
<ListBox Grid.Row="3" Grid.Column="1" MinHeight="22" Margin="2"
SelectedItem="{Binding SelectedTrack}"
ItemsSource="{Binding Tracks}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Width="Auto" Height="Auto" Margin="0"
Text="{Binding Path=TrackItemId.InstanceId}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Row="0" Grid.Column="3" Height="22" Margin="2"
Content="Add"
Command="{Binding AddTrackCmd}"/>
<Button Grid.Row="1" Grid.Column="3" Height="22" Margin="2"
Content="Remove"
Command="{Binding RemoveTrackCmd}"/>
</Grid>
</GroupBox>
. . .
Then, add the following to your view model:
. . .
public ICommand AddTrackCmd { get { return new DelegateCommand(AddTrack, CanAddTrack); } }
public ICommand RemoveTrackCmd { get { return new DelegateCommand(RemoveTrack, CanRemoveTrack); } }
. . .
public string NewTrack { get; set; }
public ITrackData SelectedTrack
{
get { return _selectedTrack; }
set
{
if (_selectedTrack != null && _isDirty)
{
var trackResult = _trackServiceEngine.GetTrackData(SelectedTrackList, _selectedTrack.TrackItemId.InstanceId);
_selectedTrack = trackResult.Length > 0 ? trackResult[0] : null;
}
_selectedTrack = value;
SelectedField = null;
Fields = new ObservableCollection<FieldDefItem>();
if (SelectedTrack != null)
{
foreach (var pair in SelectedTrack.Fields)
{
Fields.Add(new FieldDefItem (pair ));
}
}
NotifyPropertyChanged(() => SelectedTrack);
}
}
public ITrackData[] Tracks { get; private set; }
public bool ActiveTrackIdFilter
{
get { return _activeTrackIdFilter; }
set
{
_activeTrackIdFilter = value;
RefreshTrackDisplay();
}
}
public bool ActiveTagFilter
{
get { return _activeTagFilter; }
set
{
_activeTagFilter = value;
RefreshTrackDisplay();
}
}
public string TrackIdFilter { get; set; }
. . .
private void AddTrack(object obj)
{
UpdateTrack(NewTrack, _defPos, 90.0, 5.0, DateTime.UtcNow, true);
RefreshTrackDisplay();
}
private bool CanAddTrack(object obj)
{
return SelectedTrackList != null && !string.IsNullOrWhiteSpace(NewTrack) && !ExistingTrack();
}
private bool ExistingTrack()
{
foreach (var track in Tracks)
{
if (NewTrack == track.TrackItemId.InstanceId)
return true;
}
return false;
}
private void RemoveTrack(object obj)
{
_trackServiceEngine.RemoveTrack(SelectedTrackList, SelectedTrack.TrackItemId.InstanceId);
RefreshTrackDisplay();
}
private bool CanRemoveTrack(object obj)
{
return SelectedTrackList != null && SelectedTrack != null;
}
. . .
internal void RefreshTrackDisplay()
{
Tracks = _trackServiceEngine.GetAllTracks(SelectedTrackList, ActiveTrackIdFilter, TrackIdFilter, ActiveTagFilter, TagFilterKey, TagFilterValue);
NotifyPropertyChanged(() => NewTrack);
NotifyPropertyChanged(() => SelectedTrack);
NotifyPropertyChanged(() => Tracks);
NotifyPropertyChanged(() => ActiveTrackIdFilter);
NotifyPropertyChanged(() => TrackIdFilter);
}
. . .
Handle the text changed events for the text boxes in the "Code behind":
. . .
private void NewTrackChanged(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
_vm.NewTrack = textbox.Text;
_vm.RefreshTrackDisplay();
}
}
private void TrackIdFilterChanged(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
_vm.TrackIdFilter = textbox.Text;
_vm.RefreshTrackDisplay();
}
}
. . .
Edit track information
Add the following to your window xaml:
<GroupBox Grid.Row="6" Header="Edit track" IsEnabled="{Binding EditableTrack}" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Margin="2"
Content="Track id" />
<TextBlock Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Margin="2"
Text="{Binding CurrentId}"/>
<Button Grid.Row="0" Grid.Column="3" Height="22" Margin="2,4"
Content="Save"
Command="{Binding SaveTrackCmd}"/>
<Label Grid.Row="1" Grid.Column="0" Margin="2"
Content="Position" />
<TextBox Grid.Row="1" Grid.Column="1" Margin="2"
Text="{Binding CurrentPos}"
TextChanged="PositionChanged"/>
<Label Grid.Row="2" Grid.Column="0" Margin="2"
Content="Course" />
<TextBox Grid.Row="2" Grid.Column="1" Margin="2"
Text="{Binding CurrentCourse}" TextAlignment="Right"
TextChanged="CourseChanged"/>
<Label Grid.Row="3" Grid.Column="0" Margin="2"
Content="Speed" />
<TextBox Grid.Row="3" Grid.Column="1" Margin="2"
Text="{Binding CurrentSpeed}" TextAlignment="Right"
TextChanged="SpeedChanged"/>
<Label Grid.Row="4" Grid.Column="0" Margin="2"
Content="Time" />
<xctk:DateTimePicker Grid.Row="4" Grid.Column="1" Margin="2"
Format="Custom" FormatString="yyyy.MM.dd HH:mm:ss"
ShowButtonSpinner="False"
Value="{Binding TimeStamp}"
IsEnabled="{Binding TimeEnabled}" TimeFormatString="HH:mm:ss" />
<CheckBox Grid.Row="4" Grid.Column="2" VerticalAlignment="Center"
Content="Use current time"
IsChecked="{Binding UseCurrentTime}" Margin="0,8"/>
<Label Grid.Row="5" Grid.Column="0"
Content="Available tags" />
<ListView Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Margin="2"
HorizontalContentAlignment="Stretch"
SelectedItem="{Binding SelectedField}"
ItemsSource="{Binding Fields}"
SizeChanged="EqualSpaceListViewSizeChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="Tag" Width="auto" DisplayMemberBinding="{Binding Key}" />
<GridViewColumn Header="Value" Width="auto" DisplayMemberBinding="{Binding Value}" />
</GridView>
</ListView.View>
</ListView>
<Label Grid.Row="6" Grid.Column="0" Margin="2"
Content="Tag and value" />
<TextBox Grid.Row="6" Grid.Column="1" Margin="2"
Text="{Binding SelectedFieldKey}"
TextChanged="SelectedFieldKeyChanged"/>
<TextBox Grid.Row="6" Grid.Column="2" Margin="2"
Text="{Binding SelectedFieldValue}"/>
<Button Grid.Row="6" Grid.Column="3" Height="22" Margin="2,4"
Content="Add or update"
Command="{Binding UpdateFieldsCmd}"/>
</Grid>
</GroupBox>
And the following to your view model:
. . .
public ICommand UpdateFieldsCmd { get { return new DelegateCommand(AddOrUpdateField, CanAddOrUpdateField); } }
public ICommand SaveTrackCmd { get { return new DelegateCommand(SaveTrack, CanSaveTrack); } }
. . .
public bool ValidTrack { get { return SelectedTrack != null ; } }
public string CurrentId { get { return SelectedTrack?.TrackItemId.InstanceId; } }
public string CurrentPos
{
get { return SelectedTrack != null && SelectedTrack.Pos.HasValue ? SelectedTrack.Pos.Value.ToString(PositionFormat.GeoDMS) : "-"; }
set
{
if (SelectedTrack == null)
return;
GeoPos pos;
if (GeoPos.TryParse(value, PositionFormat.GeoDMS, out pos))
{
SelectedTrack.Pos = pos;
_isDirty = true;
}
NotifyPropertyChanged(() => CurrentPos);
}
}
public string CurrentCourse
{
get { return SelectedTrack != null && SelectedTrack.Course.HasValue ? SelectedTrack.Course.Value.ToString("N1") : "-"; }
set
{
if (SelectedTrack == null)
return;
double course;
if (double.TryParse(value, out course ))
{
SelectedTrack.Course = course;
_isDirty = true;
}
NotifyPropertyChanged(() => CurrentCourse);
}
}
public string CurrentSpeed
{
get { return SelectedTrack != null && SelectedTrack.Speed.HasValue ? SelectedTrack.Speed.Value.ToString("N1") : "-"; }
set
{
if (SelectedTrack == null)
return;
double speed;
if (double.TryParse(value, out speed))
{
SelectedTrack.Speed = speed;
_isDirty = true;
}
NotifyPropertyChanged(() => CurrentSpeed);
}
}
public DateTime TimeStamp
{
get { return SelectedTrack != null && SelectedTrack.ObservationTime.HasValue ? SelectedTrack.ObservationTime.Value : DateTime.MinValue; }
set
{
if (SelectedTrack != null)
{
SelectedTrack.ObservationTime = value;
_isDirty = true;
}
NotifyPropertyChanged(() => TimeStamp);
}
}
public bool TimeEnabled { get { return SelectedTrack != null && !UseCurrentTime; } }
public bool UseCurrentTime
{
get { return _useCurrentTime; }
set
{
_useCurrentTime = value;
_isDirty = true;
RefreshTrackEditDisplay();
}
}
public string SelectedFieldKey
{
get { return !string.IsNullOrWhiteSpace(_selectedFieldKey) ? _selectedFieldKey : ""; }
set
{
_selectedFieldKey = value;
NotifyPropertyChanged(() => SelectedFieldKey);
}
}
public string SelectedFieldValue
{
get { return !string.IsNullOrWhiteSpace(_selectedFieldValue) ? _selectedFieldValue : ""; }
set
{
_selectedFieldValue = value;
NotifyPropertyChanged(() => SelectedFieldValue);
}
}
public FieldDefItem SelectedField
{
get { return _selectedField; }
set
{
_selectedField = value;
SelectedFieldKey = _selectedField?.Key;
SelectedFieldValue = _selectedField?.Value;
NotifyPropertyChanged(() => SelectedFieldKey);
}
}
public ObservableCollection<FieldDefItem> Fields { get; private set; }
. . .
private void AddOrUpdateField(object obj)
{
var found = false;
foreach (var field in Fields)
{
if (field.Key == SelectedFieldKey)
{
field.Value = SelectedFieldValue;
found = true;
}
}
if (!found)
Fields.Add(new FieldDefItem(SelectedFieldKey, SelectedFieldValue));
SelectedTrack.Fields[SelectedFieldKey] = SelectedFieldValue;
_isDirty = true;
RefreshTrackEditDisplay();
}
private bool CanAddOrUpdateField(object obj)
{
return SelectedTrackList != null && SelectedTrack != null && !string.IsNullOrWhiteSpace(_selectedFieldKey);
}
private void SaveTrack(object obj)
{
if (UseCurrentTime)
SelectedTrack.ObservationTime = DateTime.UtcNow;
_trackServiceEngine.AddOrUpdateTrack(SelectedTrackList, SelectedTrack);
_isDirty = false;
RefreshTrackEditDisplay();
}
private bool CanSaveTrack(object obj)
{
return _isDirty || UseCurrentTime;
}
. . .
private void RefreshTrackEditDisplay()
{
NotifyPropertyChanged(() => SelectedTrack);
NotifyPropertyChanged(() => ValidTrack);
NotifyPropertyChanged(() => EditableTrack);
NotifyPropertyChanged(() => UseCurrentTime);
NotifyPropertyChanged(() => TimeEnabled);
NotifyPropertyChanged(() => CurrentId);
NotifyPropertyChanged(() => CurrentPos);
NotifyPropertyChanged(() => CurrentSpeed);
NotifyPropertyChanged(() => CurrentCourse);
NotifyPropertyChanged(() => TimeStamp);
NotifyPropertyChanged(() => Fields);
NotifyPropertyChanged(() => SelectedField);
NotifyPropertyChanged(() => SelectedFieldKey);
NotifyPropertyChanged(() => SelectedFieldValue);
}
. . .
And again, handle the text changed events for the text boxes in the "Code behind":
. . .
private void SelectedFieldKeyChanged(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
_vm.SelectedFieldKey = textbox.Text;
}
}
private void PositionChanged(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
GeoPos pos;
if (GeoPos.TryParse(textbox.Text, PositionFormat.GeoDMS, out pos))
{
_vm.CurrentPos = textbox.Text;
}
else
{
textbox.Text = _vm.CurrentPos;
}
}
}
private void CourseChanged(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
double course;
if (double.TryParse(textbox.Text, out course))
_vm.CurrentCourse = textbox.Text;
else
textbox.Text = _vm.CurrentCourse ;
}
}
private void SpeedChanged(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
double speed;
if (double.TryParse(textbox.Text, out speed))
_vm.CurrentSpeed = textbox.Text;
else
textbox.Text = _vm.CurrentSpeed;
}
}
. . .
private void EqualSpaceListViewSizeChanged(object sender, SizeChangedEventArgs e)
{
ListView lv = sender as ListView;
GridView gv = lv.View as GridView;
var actualWidth = lv.ActualWidth - (SystemParameters.VerticalScrollBarWidth + 10); // Adjust for scrollbar and some extra...
if (gv.Columns.Count == 0)
return;
var deltaWidth = actualWidth / gv.Columns.Count;
foreach (var col in gv.Columns)
{
col.Width = deltaWidth;
}
}
. . .
Track filtering by tag fields
Now that we can display
Auto refresh track info
. . .