POST
|
Hi Joe,
The ExportDeltaAsync is based on the last sync time on the geodatabase. I just tested the following code, if there's a syncGeodatabase happened in between, no delta is created. Code snippet against sample server is shared below.
HasEdits only reset after edits are applied/sync'd or undone/rolled back. Edits in a mobile geodatabase can be wrapped in explicit transaction by gdb.Begin/Commit/RollbackTransaction().
If you're uploading client delta a different way, the API will not have information about the last acknowledged update to compare with the edit and gdb tracking fields. Geodatabase.hasLocalEdits(), ArcGISFeatureTable.hasLocalEdits() and ArcGISFeatureTable.getLocalEditsAsync() are all based on this time. There's a GeodatabaseFeatureTable.getHasLocalEditsSince() with DateTimeOffset parameter that you could use but it only returns boolean.
Is there something in the current sync workflow that can be improved to support your custom sync processes?
private const string FeatureServiceUrl = "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Sync/SaveTheBaySync/FeatureServer";
private async Task TestExportDeltaAsync(bool syncBeforeExport = false)
{
try
{
var task = await GeodatabaseSyncTask.CreateAsync(new Uri(FeatureServiceUrl));
var areaOfInterest = task.ServiceInfo?.FullExtent;
ArgumentNullException.ThrowIfNull(areaOfInterest);
var parameters = await task.CreateDefaultGenerateGeodatabaseParametersAsync(areaOfInterest);
var pathToGeodatabase = $@"C:\dev\gdb\{Guid.NewGuid()}.geodatabase";
Debug.WriteLine(pathToGeodatabase);
var job = task.GenerateGeodatabase(parameters, pathToGeodatabase);
var gdb = await job.GetResultAsync();
// introduce an edit
areaOfInterest = gdb.GenerateGeodatabaseGeometry?.Extent;
ArgumentNullException.ThrowIfNull(areaOfInterest);
if (gdb.GetGeodatabaseFeatureTable(0) is GeodatabaseFeatureTable table)
{
await table.LoadAsync();
if (table.GeometryType == GeometryType.Point
&& table.FeatureTypes.Count > 0
&& !string.IsNullOrEmpty(table.LayerInfo?.DisplayFieldName))
{
var random = new Random();
var index = random.Next(0, table.FeatureTypes.Count - 1);
var featureType = table.FeatureTypes[index];
double x = areaOfInterest.XMin + random.NextDouble() * areaOfInterest.Width;
double y = areaOfInterest.YMin + random.NextDouble() * areaOfInterest.Height;
var point = new MapPoint(x, y, areaOfInterest.SpatialReference);
var feature = table.CreateFeature(featureType, point);
feature.SetAttributeValue(table.LayerInfo.DisplayFieldName, $"Added on {DateTimeOffset.UtcNow}");
await table.AddFeatureAsync(feature);
}
}
if (syncBeforeExport)
{
var syncParameters = await task.CreateDefaultSyncGeodatabaseParametersAsync(gdb);
var syncJob = task.SyncGeodatabase(syncParameters, gdb);
await syncJob.GetResultAsync();
}
var deltaPath = $@"{gdb.Path.Replace(".geodatabase", "")}-delta.geodatabase";
var hasDeltaExported = await GeodatabaseSyncTask.ExportDeltaAsync(gdb, deltaPath);
Debug.WriteLine($"Exported? {hasDeltaExported}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private async void OnExportDelta(object sender, RoutedEventArgs e)
{
await TestExportDeltaAsync(true);
await TestExportDeltaAsync(false);
}
Thanks.
Jennifer
... View more
09-25-2024
11:21 AM
|
0
|
0
|
177
|
POST
|
No problem. The NumberOfFeatures would be a cumulative value of the features retrieved in the table so far. So if you have this table rendered as a layer on a map, a query with view extent would have already run to fetch features. Or if you had previous queries made with different fips value. There is a QueryFeatureCountAsync method if you only want the count for features from a specific query. But if you will be working on the features returned from QueryFeaturesAsync then you can use features.Count() instead where features is the return value of the awaited query task.
... View more
07-24-2024
07:32 AM
|
1
|
0
|
376
|
POST
|
I don't see anything wrong with how you formed the query. String equality looks correct provided the field exists with the correct name and type. If you want query to return just one, you can set MaxFeatures = 1; but if you say this value is unique then you should expect a single feature returned without MaxFeatures. var attributeValue = "270530265081";
var table = BlockGroupGeoPackage.GeoPackageFeatureTables[0];
var tableField = table.GetField("fips");
var query = new QueryParameters()
{
WhereClause = $"{tableField.Name} = '{attributeValue}'",
MaxFeatures = 1
};
I would await the result of query though and may be inspect the features that come back. Output window should have the attribute value for each feature. var features = await table.QueryFeaturesAsync(query);
foreach(var feature in features)
{
// Consider printing other attributes to identify the feature (i.e. OBJECTID)
System.Diagnostics.Debug.WriteLine($"{tableField.Name}: feature.Attribute[tableField.Name]")
}
... View more
07-23-2024
06:26 PM
|
0
|
2
|
444
|
POST
|
I do not see anything wrong with your code that could've led to this error. Just a suggestion (but likely not relevant to the error you're seeing) since you are awaiting the result of syncJob.GetResultAsync() already in a try-catch. There is no need to call syncJob.Start() or handle success/fail in JobChanged. Based on the API name, I think you are using an older version of ArcGIS Maps SDK for .NET. One thing I would like to suggest (if you're able) is try the same request with latest 200.4. The equivalent event for JobChanged is StatusChanged. There is also a MessageAdded that could provide some insight at what stage this error happens (if it still happens). There could be a number of things that could result to this generic server error. Are you able to inspect ArcGISWebException.Details property? According to this doc, one possibility is the replica GUID no longer exists on server. If you have access to the ArcGIS Server Logs, it may give more information on the GP Server error. You can also see if you are hitting these support issues: https://support.esri.com/en-us/knowledge-base/error-code-400-description-unable-to-complete-operation-000020342 https://support.esri.com/en-us/knowledge-base/problem-unable-to-sync-services-in-arcgis-server-000027501 Another case that I've seen in my sync testing, it's possible for sync to fail to acquire the necessary lock to apply delta changes or have synchronization conflicts that need to be resolved.
... View more
06-04-2024
09:17 AM
|
0
|
0
|
359
|
POST
|
Thanks for following-up and sharing with us the root of the problem. I am curious to know how the table was created and why ServiceGeodatabase do not see this edit. If you loaded the feature service from a webmap or called ServiceGeodatabase.getTable() to create the ServiceFeatureTable, the ServiceFeatureTable will have a ServiceGeodatabase property. You'd see ServiceGeodatabase.connectedTables include this table. Your feature should have access to the same ServiceGeodatabase. If however, you used a ServiceFeatureTable constructor, then the table will not have a ServiceGeodatabase. You can add a check to ServiceGeodatabase.hasLocalEdits() or ServiceFeatureTable.hasLocalEdits(), before calling the appropriate applyEdits. If this returns false, there are no edits to send to server. It is best to use ServiceGeodatabase, for these reasons: https://developers.arcgis.com/net/edit-features/apply-edits/ if (feature.FeatureTable is ServiceFeatureTable sft && sft.ServiceGeodatabase is ServiceGeodatabase sgdb)
{
if (sgdb.HasLocalEdits())
{
await sgdb.ApplyEditsAsync();
}
}
... View more
04-08-2024
09:13 AM
|
0
|
0
|
598
|
POST
|
Could your ApplyEdits be wrapped in a try-catch? Can you see if exception has message/details? Could the new feature be rejected by server because of geometry (has or lack of m/z-value, spatial reference, outside layer extent) or attributes (any unspecified required fields, data type mismatch, domain errors, or perhaps constraint rule violation)? Few other things you can try: After addFeatureAsyc, check getAddedFeaturesCountAsync to ensure new feature was added. Before applyEdits subscribe to ArcGISHttpClientHandler events: HttpBeginRequest and HttpResponseEnd. You can check request URI on Begin to ensure an /applyEdits request was made. And read content as string on End to ensure an appropriate server response in JSON was received. This should provide objectid or globalid when successful or an error code/message. If the message is the generic unable to complete, you can check server logs for verbose message if you have access to the server.
... View more
04-05-2024
06:37 AM
|
1
|
1
|
645
|
POST
|
I used your code to generate geodatabase from a feature service portal item but I only see 1 replica created. We also have branch versioning enabled on this feature service. What ArcGIS Enterprise version are you using? I tried ArcGIS Enterprise 11.0, utility network version 6. ArcGIS Runtime WPF build 200.2.
... View more
11-14-2023
01:20 PM
|
0
|
0
|
901
|
POST
|
You can try the following simplified sample that contains the MapView with GraphicsOverlay for displaying the new geometry and some buttons that Start/Stop/DeleteVertex on GeometryEditor. Using the PropertyChanged event of the GeometryEditor, you can check its Geometry and update its VertexTool properties. The PolylineBuilder's IsSketchValid currently checks the minimum required number of points for a polyline so having two unique points is considered valid. Per Shelly's recommendation, if you want to continue to edit the geometry, you can use the Tools' InteractionConfiguration to enable/disable which vertex editing is allowed. For example, disable new vertex creation. <esri:MapView x:Name="MyMapView" />
<StackPanel VerticalAlignment="Top"
HorizontalAlignment="Right">
<Button Content="Line Segment"
Click="OnDrawLine" />
<Button Content="Delete Vertex"
Click="OnDeleteVertex" />
<Button Content="Complete Line Segment"
Click="OnCompleteDraw" />
</StackPanel> public MainWindow()
{
InitializeComponent();
MyMapView.Map = new Map(SpatialReferences.WebMercator);
MyMapView.GraphicsOverlays.Add(new GraphicsOverlay()
{
Renderer = new SimpleRenderer(new SimpleLineSymbol() { Color = Color.Blue, Style = SimpleLineSymbolStyle.Solid, Width = 2 })
});
MyMapView.GeometryEditor.PropertyChanged += OnGeometryPropertyChanged;
}
private bool EnsureTwoPoints => MyMapView.GeometryEditor?.Geometry is Polyline polyline &&
new PolylineBuilder(polyline).IsSketchValid;
private void OnGeometryPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(GeometryEditor.Geometry))
{
if (MyMapView.GeometryEditor.Tool is VertexTool vertexTool)
{
vertexTool.Configuration.AllowVertexCreation = !EnsureTwoPoints;
}
}
}
private void OnDrawLine(object sender, RoutedEventArgs e)
{
if (MyMapView.GeometryEditor.IsStarted)
{
return;
}
MyMapView.GeometryEditor.Start(GeometryType.Polyline);
}
private void OnDeleteVertex(object sender, RoutedEventArgs e)
{
if (!MyMapView.GeometryEditor.IsStarted)
return;
if (MyMapView.GeometryEditor.SelectedElement is GeometryEditorVertex)
MyMapView.GeometryEditor.DeleteSelectedElement();
}
private void OnCompleteDraw(object sender, RoutedEventArgs e)
{
if (!MyMapView.GeometryEditor.IsStarted || !EnsureTwoPoints)
return;
var geometry = MyMapView.GeometryEditor.Stop();
if (MyMapView.GraphicsOverlays.FirstOrDefault() is GraphicsOverlay overlay)
{
overlay.Graphics.Add(new Graphic(geometry));
}
} Click Line Segment button to start drawing Click Delete Vertex button to remove selected vertex Click Complete Line Segment button to stop drawing. Notice in this small sample code, vertex creation is only allowed when you have not met the minimum 2 points.
... View more
11-13-2023
09:05 AM
|
1
|
0
|
879
|
POST
|
You can subscribe to `GeometryEditor.PropertyChanged` event and monitor the `GeometryEditor.Geometry` property. If this is a polyline, you can use `PolylineBuilder` it's `IsSketchValid()` method already checks for the minimum set, 2 unique points. You can check the code-snippet in the Asynchronous start task with geometry result section of this blog post. You can have it throw an error or call `GeometryEditor.Stop()` so drawing is completed once you have at most 2 points.
... View more
11-06-2023
01:56 PM
|
0
|
0
|
941
|
BLOG
|
Thank you to our dear MVP's for remaining engaged in our esri community! Your feedback and contributions are most invaluable not only to your fellow developers using the Native Maps SDK (Runtime); but especially to us, in the development team, who are continuously learning, growing, and building the product with you. Thank you!
... View more
05-26-2023
09:42 AM
|
4
|
0
|
5068
|
POST
|
Inspecting fiddler capture will definitely help you troubleshoot whether the query you're making on the browser is identical to the request made through Runtime. In addition should they be different... A quick check if you will need to use paging query is to FeatureTable.QueryFeatureCountAsync if the result is more than the LayerInfo.MaxRecordCount and LayerInfo.SupportsPagination is true, you can pass a ResultOffset and MaxFeaturesCount in the QueryParameters. Another cause why query result count is different from server is you may have set a DefinitionExpression on the table which will limit the features accessible to you.
... View more
05-26-2023
09:30 AM
|
1
|
0
|
711
|
POST
|
Thanks for your feedback. You are right that there's no way of updating or providing your own predicate for AddCommand to have it respond only to touch event. How are you passing the CommandParameter for AddCommand? This is only enabled with MapPoint. If you don't want AddCommand to execute and add vertex to your polyline/polygon, could you may be provide MapPoint vertex only when a touch gesture is detected? Alternatively, you can call InsertVertexAfterSelectedVertex method with a more restrictive check. Or you may pause SketchEditor from responding to interaction using its IsEnabled property. If only vertex-editing need to be suspended you can set SketchEditConfiguration.VertexEditMode to SelectionOnly.
... View more
04-15-2021
09:53 AM
|
1
|
1
|
934
|
POST
|
Does layer.InitializeAsync trigger a challenge if you subscribe to ChallengeHandler? IdentityManager.Current.ChallengeHandler = new ChallengeHandler(async (info) =>
{
var cred = await
IdentityManager.Current.GenerateCredentialAsync(info.ServiceUri, "<username>", "<password>");
return cred;
}); It may be possible that you need to AddCredential for ServiceUri that match server https://<portal server>/server/rest
... View more
04-15-2021
09:52 AM
|
0
|
1
|
2035
|
POST
|
Thanks for reporting this bug. I can reproduce that updating vertex by interaction allows undo/redo while updating vertex by code with MoveSelectedVertex, cannot be undone without the vertex being deleted. It also appears that GeometryChanged event does not report this as move vertex but as move geometry. As a workaround, you may subscribe to SelectedVertexChanged event and use this to track the newly inserted vertex (e.NewVertex.Point will be the unmodified/unsnapped vertex). Whether you interactively add point or call InsertAfterSelectedVertex, this event will fire.
... View more
02-16-2021
08:47 AM
|
1
|
0
|
1157
|
POST
|
There may be a few SketchEditor commands that you can specify in XAML (like Complete/Cancel/Undo/Redo/Delete). However, you can only begin a draw in code-behind using one of the StartAsync methods. Based on SketchCreation mode, shape is drawn based on MapView events. For example, tap/click for point or adding vertices in polyline/polygon, drag/move for freehand, arrow, rectangle, triangle, circle, ellipse shapes. Few XAML example code would be to set DataContext to MapView's SketchEditor and use Command Binding. <Grid DataContext="{Binding ElementName=MyMapView,Path=SketchEditor}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding IsEnabled, Mode=TwoWay}"
Content="IsEnabled" />
<CheckBox IsChecked="{Binding IsVisible, Mode=TwoWay}"
Content="IsVisible"
Grid.Column="1" />
<Slider Minimum="0"
Maximum="1"
Value="{Binding Opacity, Mode=TwoWay}"
Grid.ColumnSpan="2"
Grid.Row="1" />
<Button x:Name="AddButton"
Content="Add"
Command="{Binding AddCommand}"
Grid.Row="2" />
<Button Content="Delete"
Command="{Binding DeleteCommand}"
Grid.Row="2"
Grid.Column="1" />
<Button Content="Undo"
Command="{Binding UndoCommand}"
Grid.Row="3" />
<Button Content="Redo"
Command="{Binding RedoCommand}"
Grid.Row="3"
Grid.Column="1" />
<Button Content="Cancel"
Command="{Binding CancelCommand}"
Grid.Row="4" />
<Button Content="Complete"
Command="{Binding CompleteCommand}"
Grid.Row="4"
Grid.Column="1" />
</Grid> If you have provided SketchEditorConfiguration in resource, you can access this by key and update it's properties using XAML-binding too. <Window.Resources>
<esri:SketchEditConfiguration x:Key="MySketchEditConfiguration" />
</Window.Resources>
<StackPanel DataContext="{StaticResource MySketchEditConfiguration}">
<ComboBox x:Name="ResizeModes"
SelectedItem="{Binding ResizeMode, Mode=TwoWay}" />
<CheckBox IsChecked="{Binding RequireSelectionBeforeDrag, Mode=TwoWay}"
Content="RequireSelectionBeforeDrag" />
<CheckBox IsChecked="{Binding AllowMove, Mode=TwoWay}"
Content="AllowMove" />
<ComboBox x:Name="VertexEditModes"
SelectedItem="{Binding VertexEditMode, Mode=TwoWay}" />
<CheckBox IsChecked="{Binding AllowVertexEditing, Mode=TwoWay}"
Content="AllowVertexEditing" />
<CheckBox IsChecked="{Binding AllowRotate, Mode=TwoWay}"
Content="AllowRotate" />
</StackPanel>x Depending whether you are creating a new shape or editing an existing geometry, you may call any of the StartAsync methods. var editConfig = this.Resources["MySketchEditConfiguration"] as SketchEditConfiguration;
var geometry = await MyMapView.SketchEditor.StartAsync(creationMode, editConfig);
... View more
11-10-2020
09:36 AM
|
0
|
0
|
1284
|
Title | Kudos | Posted |
---|---|---|
1 | 07-24-2024 07:32 AM | |
1 | 04-05-2024 06:37 AM | |
1 | 11-13-2023 09:05 AM | |
1 | 04-26-2011 06:50 PM | |
1 | 05-26-2023 09:30 AM |
Online Status |
Offline
|
Date Last Visited |
4 weeks ago
|