Skip to content

Commit b80a66e

Browse files
[Automated] Sync v.next with main (#1679)
Co-authored-by: Praveenaa Kulandhaivel <[email protected]>
1 parent 0294256 commit b80a66e

File tree

30 files changed

+2721
-98
lines changed

30 files changed

+2721
-98
lines changed

src/MAUI/Maui.Samples/ArcGIS.Samples.Maui.csproj

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@
134134
<PackageReference Include="Esri.Calcite.Maui" />
135135
<PackageReference Include="Markdig" />
136136
<PackageReference Include="System.Drawing.Common" />
137-
<PackageReference Include="Microsoft.Maui.Controls"/>
138-
<PackageReference Include="Microsoft.Maui.Controls.Compatibility"/>
137+
<PackageReference Include="Microsoft.Maui.Controls" />
138+
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" />
139139
</ItemGroup>
140140

141141
<!-- WinUIEx is used to workaround the lack of a WebAuthenticationBroker for WinUI. https://github.com/microsoft/WindowsAppSDK/issues/441 -->
@@ -165,6 +165,12 @@
165165
<MauiAsset Update="Converters\*.cs">
166166
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
167167
</MauiAsset>
168+
<Compile Update="Samples\Search\QueryDynamicEntities\CustomStreamService.cs">
169+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
170+
</Compile>
171+
<Compile Update="Samples\Search\QueryDynamicEntities\FlightInfo.cs">
172+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
173+
</Compile>
168174
<MauiXaml Update="Controls\CategoriesFlyoutContent.xaml">
169175
<Generator>MSBuild:Compile</Generator>
170176
</MauiXaml>
Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
{
2-
"category": "Layers",
3-
"description": "Change the appearance of a 3D object scene layer with different renderers.",
4-
"formal_name": "ApplyRenderersToSceneLayer",
5-
"ignore": false,
6-
"images": [
7-
"applyrendererstoscenelayer.jpg"
8-
],
9-
"keywords": [
10-
"3d tiles",
11-
"OGC",
12-
"OGC API",
13-
"layers",
14-
"scene",
15-
"service"
16-
],
17-
"offline_data": [],
18-
"redirect_from": [],
19-
"relevant_apis": [
20-
"ArcGISScene",
21-
"ArcGISSceneLayer",
22-
"ClassBreaksRenderer",
23-
"MultilayerMeshSymbol",
24-
"SceneView",
25-
"SimpleRenderer",
26-
"SymbolLayerEdges3D",
27-
"UniqueValueRenderer"
28-
],
29-
"snippets": [
30-
"ApplyRenderersToSceneLayer.xaml.cs",
31-
"ApplyRenderersToSceneLayer.xaml"
32-
],
33-
"title": "Apply renderers to scene layer"
2+
"category": "Layers",
3+
"description": "Change the appearance of a 3D object scene layer with different renderers.",
4+
"formal_name": "ApplyRenderersToSceneLayer",
5+
"ignore": false,
6+
"images": [
7+
"applyrendererstoscenelayer.jpg"
8+
],
9+
"keywords": [
10+
"3d tiles",
11+
"OGC",
12+
"OGC API",
13+
"layers",
14+
"scene",
15+
"service"
16+
],
17+
"offline_data": [],
18+
"redirect_from": [],
19+
"relevant_apis": [
20+
"ArcGISScene",
21+
"ArcGISSceneLayer",
22+
"ClassBreaksRenderer",
23+
"MultilayerMeshSymbol",
24+
"SceneView",
25+
"SimpleRenderer",
26+
"SymbolLayerEdges3D",
27+
"UniqueValueRenderer"
28+
],
29+
"snippets": [
30+
"ApplyRenderersToSceneLayer.xaml.cs",
31+
"ApplyRenderersToSceneLayer.xaml"
32+
],
33+
"title": "Apply renderers to scene layer"
3434
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// Copyright 2025 Esri.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
5+
//
6+
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
7+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
8+
// language governing permissions and limitations under the License.
9+
10+
using Esri.ArcGISRuntime.Geometry;
11+
using Esri.ArcGISRuntime.RealTime;
12+
using System.Text.Json;
13+
14+
namespace ArcGIS.Samples.QueryDynamicEntities
15+
{
16+
public class CustomStreamService : DynamicEntityDataSource
17+
{
18+
private readonly DynamicEntityDataSourceInfo _info;
19+
private readonly string _dataPath;
20+
private readonly TimeSpan _delay;
21+
private CancellationTokenSource _cancellationTokenSource;
22+
private Task _dataFeedTask;
23+
24+
// Initializes the custom stream service with data source info and file path.
25+
public CustomStreamService(DynamicEntityDataSourceInfo info, string dataPath, TimeSpan delay)
26+
{
27+
_info = info;
28+
_dataPath = dataPath;
29+
_delay = delay;
30+
}
31+
32+
// Returns the data source information while loading the service.
33+
protected override Task<DynamicEntityDataSourceInfo> OnLoadAsync() =>
34+
Task.FromResult(_info);
35+
36+
// Starts the data feed processing task when connecting to the service.
37+
protected override Task OnConnectAsync(CancellationToken cancellationToken)
38+
{
39+
_cancellationTokenSource = new CancellationTokenSource();
40+
_dataFeedTask = ProcessDataFeedAsync(_cancellationTokenSource.Token);
41+
return Task.CompletedTask;
42+
}
43+
44+
// Cancels the data feed processing task and cleans up resources when disconnecting from the service.
45+
protected override async Task OnDisconnectAsync()
46+
{
47+
_cancellationTokenSource?.Cancel();
48+
49+
if (_dataFeedTask != null)
50+
{
51+
try
52+
{
53+
await _dataFeedTask;
54+
}
55+
catch (OperationCanceledException)
56+
{
57+
}
58+
}
59+
60+
_cancellationTokenSource?.Dispose();
61+
}
62+
63+
// Reads and processes flight data from JSON file line by line with delays.
64+
private async Task ProcessDataFeedAsync(CancellationToken cancellationToken)
65+
{
66+
try
67+
{
68+
if (!File.Exists(_dataPath))
69+
throw new FileNotFoundException("Flight data file not found.", _dataPath);
70+
71+
// Read all lines off the UI thread. Each line should contain one JSON object.
72+
var lines = await File.ReadAllLinesAsync(_dataPath, cancellationToken);
73+
74+
foreach (var line in lines)
75+
{
76+
if (cancellationToken.IsCancellationRequested) break;
77+
78+
try
79+
{
80+
// Parse a single JSON line (newline-delimited JSON format).
81+
using (JsonDocument document = JsonDocument.Parse(line))
82+
{
83+
var root = document.RootElement;
84+
85+
// Geometry section (expected: { "geometry": { "x": <double>, "y": <double> } })
86+
if (root.TryGetProperty("geometry", out JsonElement geometryElement))
87+
{
88+
double x = 0, y = 0;
89+
90+
// Extract X coordinate (defaults remain 0 if missing or invalid).
91+
if (geometryElement.TryGetProperty("x", out JsonElement xElement))
92+
x = xElement.GetDouble();
93+
94+
// Extract Y coordinate.
95+
if (geometryElement.TryGetProperty("y", out JsonElement yElement))
96+
y = yElement.GetDouble();
97+
98+
// Create geometry in WGS84.
99+
var point = new MapPoint(x, y, SpatialReferences.Wgs84);
100+
101+
// Collect attribute key/value pairs.
102+
var attributes = new Dictionary<string, object>();
103+
104+
if (root.TryGetProperty("attributes", out JsonElement attributesElement))
105+
{
106+
foreach (var property in attributesElement.EnumerateObject())
107+
{
108+
object value = property.Value.ValueKind switch
109+
{
110+
JsonValueKind.String => property.Value.GetString(),
111+
JsonValueKind.Number when property.Value.TryGetInt32(out int intValue) => intValue,
112+
JsonValueKind.Number => property.Value.GetDouble(),
113+
JsonValueKind.True => true,
114+
JsonValueKind.False => false,
115+
JsonValueKind.Null => null,
116+
_ => property.Value.ToString()
117+
};
118+
119+
attributes[property.Name] = value;
120+
}
121+
}
122+
// Add the observation to the data source.
123+
AddObservation(point, attributes);
124+
}
125+
}
126+
// Introduce a delay to simulate real-time data feed.
127+
await Task.Delay(_delay, cancellationToken);
128+
}
129+
catch (JsonException ex)
130+
{
131+
System.Diagnostics.Debug.WriteLine($"Error parsing JSON line: {ex.Message}");
132+
continue;
133+
}
134+
}
135+
}
136+
catch (Exception ex)
137+
{
138+
System.Diagnostics.Debug.WriteLine($"Data feed error: {ex.Message}");
139+
}
140+
}
141+
}
142+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright 2025 Esri.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
5+
//
6+
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
7+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
8+
// language governing permissions and limitations under the License.
9+
10+
using Esri.ArcGISRuntime.RealTime;
11+
using System.Collections.Generic;
12+
using System.ComponentModel;
13+
using System.Runtime.CompilerServices;
14+
15+
namespace ArcGIS.Samples.QueryDynamicEntities
16+
{
17+
public class FlightInfo : INotifyPropertyChanged
18+
{
19+
// The dynamic entity representing the flight.
20+
public DynamicEntity Entity { get; }
21+
22+
// Backing fields for flight attributes.
23+
private string _flightNumber;
24+
private string _aircraft;
25+
private string _altitude;
26+
private string _speed;
27+
private string _heading;
28+
private string _status;
29+
private string _arrivalAirport;
30+
private bool _isExpanded;
31+
32+
// Initializes flight info with entity and subscribes to change events.
33+
public FlightInfo(DynamicEntity entity)
34+
{
35+
Entity = entity;
36+
UpdateAttributes();
37+
Entity.DynamicEntityChanged += OnEntityChanged;
38+
}
39+
40+
public bool IsExpanded
41+
{
42+
get => _isExpanded;
43+
set
44+
{
45+
if (_isExpanded != value)
46+
{
47+
_isExpanded = value;
48+
OnPropertyChanged();
49+
OnPropertyChanged(nameof(ToggleButtonText));
50+
}
51+
}
52+
}
53+
54+
// Text for the toggle button based on expansion state.
55+
public string ToggleButtonText => IsExpanded ? "Hide Details" : "Show Details";
56+
57+
// Updates field value and raises property changed event if value differs.
58+
private bool SetField<T>(ref T field, T value, [CallerMemberName] string name = null)
59+
{
60+
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
61+
field = value;
62+
OnPropertyChanged(name);
63+
return true;
64+
}
65+
66+
public string FlightNumber { get => _flightNumber; private set => SetField(ref _flightNumber, value); }
67+
public string Aircraft { get => _aircraft; private set => SetField(ref _aircraft, value); }
68+
public string Altitude { get => _altitude; private set => SetField(ref _altitude, value); }
69+
public string Speed { get => _speed; private set => SetField(ref _speed, value); }
70+
public string Heading { get => _heading; private set => SetField(ref _heading, value); }
71+
public string Status { get => _status; private set => SetField(ref _status, value); }
72+
public string ArrivalAirport { get => _arrivalAirport; private set => SetField(ref _arrivalAirport, value); }
73+
74+
// Retrieves attribute value from entity or returns default if not found.
75+
private string GetAttribute(string key, string defaultValue)
76+
{
77+
if (Entity?.Attributes != null && Entity.Attributes.TryGetValue(key, out var value))
78+
return value?.ToString() ?? defaultValue;
79+
return defaultValue;
80+
}
81+
82+
// Formats numeric string to zero decimal places or returns original if not numeric.
83+
private string FormatNumber(string value)
84+
{
85+
if (double.TryParse(value, out double number))
86+
return number.ToString("F0");
87+
return value;
88+
}
89+
90+
// Refreshes all flight attribute properties from the entity.
91+
private void UpdateAttributes()
92+
{
93+
FlightNumber = GetAttribute("flight_number", "N/A");
94+
Aircraft = GetAttribute("aircraft", "Unknown");
95+
Altitude = FormatNumber(GetAttribute("altitude_feet", "0"));
96+
Speed = FormatNumber(GetAttribute("speed", "0"));
97+
Heading = FormatNumber(GetAttribute("heading", "0"));
98+
Status = GetAttribute("status", "Unknown");
99+
ArrivalAirport = GetAttribute("arrival_airport", "N/A");
100+
}
101+
102+
// Updates attributes when entity receives new observation data.
103+
private void OnEntityChanged(object sender, DynamicEntityChangedEventArgs e)
104+
{
105+
if (e.ReceivedObservation != null)
106+
{
107+
UpdateAttributes();
108+
}
109+
}
110+
111+
// INotifyPropertyChanged implementation.
112+
public event PropertyChangedEventHandler PropertyChanged;
113+
114+
// Raises property changed event for data binding updates.
115+
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
116+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
117+
}
118+
}

0 commit comments

Comments
 (0)