POST
|
Brian, Try adding a 'using' around your Search line to ensure the rowCursor is disposed of correctly eg. using (RowCursor wsCursor = waterServiceLayer.Search(wsFilter))
{
Feature wsFeature;
//Go to the first item in the cursor, and use it as a Feature
wsCursor.MoveNext();
wsFeature = (Feature)wsCursor.Current;
if (wsFeature != null)
{
...
}
} The other thing to try would be to check the return value of editOperation.Execute and editOperation.ErrorMessage if you get a failure. Narelle
... View more
07-25-2018
08:27 AM
|
2
|
2
|
821
|
POST
|
Steve, take a look at the sample at this location arcgis-pro-sdk-community-samples/Framework/ProgressDialog at master · Esri/arcgis-pro-sdk-community-samples · GitHub It illustrates using the ProgressDialog with a ProgressSource or a CancellableProgressorSource that updates messages. Narelle
... View more
07-25-2018
08:16 AM
|
0
|
1
|
2854
|
POST
|
I'm still not seeing any problems. Here is a button click with a similar scenario to what you outlined - creating a feature with null geometry. I never see "boo" in a message box or get an exception. What version of Pro are you using?. Is there anything particular about your data or the way you're calling the feature creation? protected override async void OnClick() { bool result = await QueuedTask.Run(async () => { FeatureLayer featureLayer = MapView.Active.Map.FindLayers("Point_Paired").FirstOrDefault() as FeatureLayer; if (featureLayer == null) return false; var editOperation = new EditOperation(); var atts = new Dictionary<string, object>(); // create with empty attributes - no shape editOperation.Create(featureLayer, atts); bool creationResult = await editOperation.ExecuteAsync(); if (editOperation.IsSucceeded) { Application.Current.Dispatcher.Invoke(() => { var pane = FrameworkApplication.DockPaneManager.Find("esri_editing_AttributesDockPane"); if (pane != null) { pane.Pin(); pane.Activate(); } else ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("boo"); }); } return creationResult; }); }
... View more
07-24-2018
03:33 PM
|
0
|
0
|
1165
|
POST
|
Steve, Make sure you are on the UI thread (ie not on the background thread) when you call DockPaneManager.Find. Dockpanes are created on the UI thread and should not be accessed on the CIM / background thread. I suspect this is why you are having this problem. Narelle
... View more
07-24-2018
12:32 PM
|
0
|
2
|
1165
|
POST
|
What is the value of 'operationResult'. when you run the code? If it is false is there a useful string in op.ErrorMessage? From what you've posted here, it appears that the geometry function is calculating values successfully but it is the edit which fails to be committed. Are you able to edit this same data when using ArcGIS Pro (modify an attribute or use move/rotate/scale to modify the geometry). Narelle
... View more
07-19-2018
02:00 PM
|
0
|
0
|
971
|
POST
|
Brian, In addition you should never assume that there is always a mapview active. What if your user has a layout active? What if your user has no mapviews open. In both of these scenarios, MapView.Active will be null and MapView.Active.Map will throw a nullReferenceException as you are experiencing. Rather than wrap in a try, catch. you should add the following to your code if (MapView.Active == null) return;
... View more
04-12-2018
09:29 AM
|
1
|
0
|
929
|
POST
|
Brian, Technically the correct styling for a listView / ListViewItem in Pro looks like this (you can see ListViews styled this way on the Licensing page in the backstage) This can be achieved by the following <ListView Grid.Row="1" Margin="5" ItemsSource="{Binding MyItems}" ItemContainerStyle="{StaticResource {x:Type ListViewItem}}" SelectedItem="{Binding SelectedItem}" HorizontalContentAlignment="Stretch" IsSynchronizedWithCurrentItem="True"> </ListView> Or as Charlie mentioned - not specifying an ItemContainerStyle at all. You can of course style the ListView to look like a ListBox (with the blue border brush) if you want. The following is one way of doing it. It is a little more complicated and involves using a ControlTemplate for the ListViewItem which is necessary to ensure the 'flat / matte' background color. <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListViewItem}"> <Grid> <Border x:Name="innerBorder" Background="{TemplateBinding Background}" BorderThickness="1" CornerRadius="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true" /> <GridViewRowPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="true"> <Setter TargetName="innerBorder" Property="Background" Value="{DynamicResource Esri_BackgroundHoverBrush}" /> <Setter TargetName="innerBorder" Property="BorderBrush" Value="{DynamicResource Esri_BorderSelectedBrush}" /> </Trigger> <Trigger Property="IsSelected" Value="true"> <Setter TargetName="innerBorder" Property="Background" Value="{DynamicResource Esri_BackgroundSelectedBrush}" /> <Setter TargetName="innerBorder" Property="BorderBrush" Value="{DynamicResource Esri_BorderSelectedBrush}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ListView.ItemContainerStyle> Narelle
... View more
03-29-2018
05:20 PM
|
1
|
2
|
1999
|
POST
|
Karsten, Take a look at the Notification sample at https://github.com/Esri/arcgis-pro-sdk-community-samples/tree/master/Framework/Notifications This will show you how to add the two different types of notifications - toast notifications and notifications that appear in the notification pane. Thanks Narelle
... View more
02-05-2018
04:08 PM
|
0
|
0
|
1274
|
POST
|
Hi Samantha, As you guessed, your syntax for the MultipleRingBuffer tool is not completely correct. Here's a quick way to work out the correct syntax when you get stuck. Run the tool in Pro over a sample dataset with the required parameters. Then go to the History tab in the Catalog window and hover over the GP tool that you submitted. You can see that the Distances are separated by semi-colons rather than commas. And the final parameter should be OUTSIDE_ONLY or FULL. You can also see a lot of this information by looking at the syntax section of help page for the tool (Multiple Ring Buffer—Help | ArcGIS Desktop). Thus your example should look something like this. protected override async void OnClick() { var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(); var valueArray = await QueuedTask.Run(() => { return Geoprocessing.MakeValueArray(featureLayer, @"D:\Data\Anno\SampleAnno.gdb\SampleAnno_MultipleRingBuffer3", @"50;100;150", "Meters", "distance", "All", "FULL"); }); await Geoprocessing.ExecuteToolAsync("Analysis.MultipleRingBuffer", valueArray); } With regards to your last statement about wanting the user to be able to pick a point on the screen rather than a feature class with points, that is not possible. Again looking at the syntax section on the help page for the tool you can see that the first parameter must be of type FeatureLayer; meaning that the tool will only accept existing features in a featurelayer or a selection set of features in a featurelayer. You can use the sketch geometry to select existing features in the appropriate layer before calling the tool but you cannot pass a geometry itself. Hope this helps. Narelle
... View more
02-02-2018
11:50 AM
|
2
|
0
|
1445
|
POST
|
Taner, Unfortunately functionality to customize an annotation symbol at feature creation time at Pro 2.1 is limited. The expectation is that the symbols and templates defined on the annotation feature class are authored in such a way that additional customization is not required at creation. As you have found, when using the dictionary signature of EditOperation.Create, the value in the SymbolID field determines the symbol used for the newly created feature. Additional symbol formatting properties set in the dictionary are ignored. (The TextString field is the exception.) We are continuing to work on the annotation API and this is one of the areas identified that will be enhanced for ArcGIS Pro 2.2. In the meantime, if you still wish to customize the symbol within the same operation there are two options 1. trap for the EditCompleted event, look for the features created and update the CIMTextGraphic as you indicate you have done. 2. Use a second operation that is chained to the first which performs the CIMTextGraphic modification via the EditOperation.Callback method. Both of these options ensure you only have one item on the undo/redo stack. Here's an example of how to use a chained operation to customize the text symbol after the feature is created. protected override async Task<bool> OnSketchCompleteAsync(Geometry geometry) { if (CurrentTemplate == null || geometry == null) return false; bool result = await QueuedTask.Run(() => { // get the anno layer, feature class AnnotationLayer annoLayer = CurrentTemplate.Layer as AnnotationLayer; if (annoLayer == null) return false; var fc = annoLayer.GetFeatureClass() as ArcGIS.Core.Data.Mapping.AnnotationFeatureClass; if (fc == null) return false; // get the featureclass CIM definition which contains the labels, symbols var cimDefinition = fc.GetDefinition() as ArcGIS.Core.Data.Mapping.AnnotationFeatureClassDefinition; var labels = cimDefinition.GetLabelClassCollection(); var symbols = cimDefinition.GetSymbolCollection(); // make sure there are symbols if ((labels.Count == 0) || (symbols.Count == 0)) return false; var label = labels[0]; if (labels.Count > 1) { foreach (var LabelClass in labels) { if (LabelClass.Name == CurrentTemplate.Name) { label = LabelClass; break; } } } var symbolName = label.TextSymbol.SymbolName; int symbolID = -1; if (!int.TryParse(symbolName, out symbolID)) { foreach (var symbol in symbols) { if (symbol.Name == symbolName) { symbolID = symbol.ID; break; } } } if (symbolID == -1) return false; // Create an edit operation var createOperation = new EditOperation(); createOperation.Name = string.Format("Create {0}", CurrentTemplate.Layer.Name); createOperation.SelectNewFeatures = true; // use the dictionary to set values Dictionary<string, object> values = new Dictionary<string, object>(); values.Add("SymbolID", symbolID); values.Add("AnnotationClassID, label.ID); int idxField = cimDefinition.FindField("TextString"); if (idxField != -1) values.Add("TextString", "My annotation feature"); // set the cimTextGraphic geometry to be the sketched line values["SHAPE"] = geometry; // create and execute long newFeatureID = -1; createOperation.Create(CurrentTemplate.Layer, values, oid => newFeatureID = oid); bool opResult = createOperation.Execute(); // if success, if (opResult) { // chain an operation to customize the text symbol - chaining means that the two operations will be grouped as one on the undo/redo stack var chainedOp = createOperation.CreateChainedOperation(); chainedOp.Callback(context => { // find the feature QueryFilter qf = new QueryFilter(); qf.WhereClause = "OBJECTID = " + newFeatureID.ToString(); // make sure you use a non-recycling cursor using (var rowCursor = fc.Search(qf, false)) { rowCursor.MoveNext(); if (rowCursor.Current != null) { ArcGIS.Core.Data.Mapping.AnnotationFeature annoFeature = rowCursor.Current as ArcGIS.Core.Data.Mapping.AnnotationFeature; if (annoFeature != null) { // get the CIMTextGraphic var textGraphic = annoFeature.GetGraphic() as CIMTextGraphic; if (textGraphic != null) { var symbol = textGraphic.Symbol.Symbol; var cimTextSymbol = symbol as CIMTextSymbol; cimTextSymbol.HorizontalAlignment = ArcGIS.Core.CIM.HorizontalAlignment.Center; cimTextSymbol.VerticalAlignment = ArcGIS.Core.CIM.VerticalAlignment.Center; cimTextSymbol.SetSize(0.4); // update the graphic annoFeature.SetGraphic(textGraphic); // store annoFeature.Store(); // refresh the cache context.Invalidate(annoFeature); } } } } }, fc); // execute the chained operation chainedOp.Execute(); } return opResult; }); return result; }
... View more
01-26-2018
04:15 PM
|
0
|
0
|
651
|
POST
|
Hi taner, Thank you for pointing out this issue. Yes it is a bug. It will be fixed in the 2.2 release of the software. Narelle
... View more
01-24-2018
10:06 AM
|
0
|
0
|
567
|
POST
|
Brian, Let me see if I can clarify things a bit Any edits performed in ArcGIS Pro need to be wrapped in an EditOperation. Each EditOperation puts an item on the undo/redo stack (assuming it is a long transaction) An EditOperation can contain a single edit (for example a modify) or multiple edits at once (for example a create, 2 modifies and 3 deletes). Caveat - the multiple edits MUST be independent of each other. For example I cannot perform a create and then an attribute update of the same feature in the same EditOperation, because setting up the Modify method requires an objectID which depends on the create having been committed to the database. The edit(s) are 'committed' when the Execute or ExecuteAsync method is called For example, the following Edit operation contains a create, 2 modifies and 1 delete. This edit operation will succeed assuming that i'm modifying and deleting valid features. var op = new EditOperation();
op.Name = "Multiple edits";
op.Create(featureLayer, geometry);
op.Modify(featureLayer2, 1);
op.Modify(featureLayer3, 2);
op.Delete(featureLayer2, 3);
bool result = op.Execute(); // <= create, modifies and delete are committed here
A chained operation is simply an edit operation that links to a previous EditOperation allowing all edits from both operations to be part of the same undo/redo item. You use a chained operation when the edit you require is dependent on the results of a previous EditOperation being commited. As you can have multiple edits in an EditOperation you can also have multiple edits in a Chained operation. Using the previous example, technically there's no reason why you can't do the following with a chained operation but it is not best practice - you're adding additional overhead to the database and the code is not as easy to read or maintain. var op = new EditOperation();
op.Name = "Multiple edits";
op.Create(featureLayer, geometry);
op.Modify(featureLayer2, 1);
bool result = op.Execute(); // <= create, modify are committed here
if (result)
{
// create chained op
var chainedOp = op.CreateChainedOperation();
chainedOp.Modify(featureLayer3, 2);
chainedOp.Delete(featureLayer2, 3);
result = chainedOp.Execute(); // <= modify and delete are committed here
} The example we mostly use with chained operations is the 'create a feature and add an attachment' example. The method signature of AddAttachment requires the objectID of the feature which means that the creation needs to be committed in order for that objectID to exist. The creation occurs in the main edit operation and adding the attachment occurs in the chained operation. //create an edit operation and name.
var op1 = new EditOperation();
op1.Name = string.Format("Create point in '{0}'", CurrentTemplate.Layer.Name);
//create a new feature and return the oid.
long newFeatureID = -1;
op1.Create(CurrentTemplate, geometry, oid => newFeatureID = oid);
// newFeatureID is populated when the Execute is called
op1.Execute();
//create a chained operation and add the attachment.
var op2 = op1.CreateChainedOperation();
// use the newFeatureID and template layer to identify the new feature
op2.AddAttachment(CurrentTemplate.Layer, newFeatureID, @"C:\Hydrant.jpg");
op2.Execute();
With regards to the examples in your posts; It made sense to use the ChainedOperation in your previous post because the updates you were performing incremented values from features whose attributes were also required to be updated. You wanted all these operations to appear in one undo/redo item AND you were dependent on the attribute values of previous edit commits. The scenario in this post doesn't appear to have the same constraints; all the updates are independent of each other as the values come from the form. This is why Sean posted about not requiring the ChainedOperation. I've reworked your code into multiple snippets. The first illustrating how to perform the chainedOperation in a loop to give you an example of how it might be structured if it was required (note - this is just one way of structuring it, not the only way);. The update you posted is pretty similar to this. You're correct in saying that having to do a 'fake' edit (as per your first code snippet) is counter-intuitive... that's generally an indication that you either need to restructure your code or think of a different approach. the second snippet is the preferred solution with regards to Edit Operations to the problem in this post. It uses a single EditOperation and queues the multiple Modify methods. You should use this rather than the chainedOperation because the edits you're performing are all independent of each other and not reliant on values from a previous operation. the third snippet shows you an optimization with respect to the Inspector object. Because the selected features in each layer will have the exact same fields updated to the same values we can load the inspector once per layer with all the selected features.rather than for every feature. (you can use this optimization with the chainedOperation snippet too - i just didn't include it) snippet one - illustrates looping of a chainedOperation private void btnSave_Click(object sender, EventArgs e)
{
try
{
//Give the user a chance to get out
. if (ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Are you sure you want to update all the selected layers?", "Update Selected Features?", System.Windows.MessageBoxButton.YesNo) == System.Windows.MessageBoxResult.No)
return;
this.Cursor = Cursors.WaitCursor;
QueuedTask.Run(() =>
{
Map map = MapView.Active.Map;
//Create the MAIN edit operation...this will show up on the Undo Stack
var editOperation = new ArcGIS.Desktop.Editing.EditOperation();
editOperation.Name = "Update Multiple Features";
editOperation.EditOperationType = ArcGIS.Desktop.Editing.EditOperationType.Long;
ArcGIS.Desktop.Editing.EditOperation chainedOp = null;
// create an inspector object
var inspector = new ArcGIS.Desktop.Editing.Attributes.Inspector(true);
// set a flag - we will be using the main operation first
bool isMainOperation = true;
//Go through each layer in the Layers listbox
foreach (string layer in lstLayers.Items)
{
var currentLayer = map.FindLayers(layer).FirstOrDefault() as BasicFeatureLayer;
var selection = currentLayer.GetSelection();
IReadOnlyList<long> selectedOIDs = selection.GetObjectIDs();
foreach (var oid in selectedOIDs)
{
inspector.Clear();
inspector.Load(currentLayer, oid);
//use the current selected OBJECTID as you go through the loop of selected features
for (int i = 0; i < gridFields.Rows.Count; i++)
{
if (gridFields.Rows.Cells[1].Value != null)
{
insp[gridFields.Rows.Cells[0].Value.ToString()] = gridFields.Rows.Cells[1].Value;
}
}
if (isMainOperation)
{
// set up the edit
editOperation.Modify(inspector);
// execute it
bool result = editOperation.Execute();
// change the flag so we'll use the chainedOperation next
isMainOperation = false;
}
else
{
// only create the chained operation once
if (chainedOp == null)
chainedOp = editOperation.CreateChainedOperation();
// queue up a modify
chainedOp.Modify(inspector);
}
}
}
// finished the layer loop, lets commit anything in the chained operation
if ((chainedOp != null) && !chainedOp.IsEmpty)
{
bool chainedResult = chainedOp.Execute();
}
}); //end of QueuedTask
}
catch
{
}
finally
{
this.Cursor = Cursors.Default;
}
} snippet two - illustrates the preferred EditOperation solution - queues all edits into a single EditOperation private void btnSave_Click_NoChain(object sender, EventArgs e)
{
try
{
//Give the user a chance to get out.
if (ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Are you sure you want to update all the selected layers?", "Update Selected Features?", System.Windows.MessageBoxButton.YesNo) == System.Windows.MessageBoxResult.No)
return;
this.Cursor = Cursors.WaitCursor;
QueuedTask.Run(() =>
{
Map map = MapView.Active.Map;
//Create the MAIN edit operation...this will show up on the Undo Stack
var editOperation = new ArcGIS.Desktop.Editing.EditOperation();
editOperation.Name = "Update Multiple Features";
editOperation.EditOperationType = ArcGIS.Desktop.Editing.EditOperationType.Long;
var inspector = new ArcGIS.Desktop.Editing.Attributes.Inspector(true);
//Go through each layer in the Layers listbox
foreach (string layer in lstLayers.Items)
{
var currentLayer = map.FindLayers(layer).FirstOrDefault() as BasicFeatureLayer;
var selection = currentLayer.GetSelection();
IReadOnlyList<long> selectedOIDs = selection.GetObjectIDs();
foreach (var oid in selectedOIDs)
{
inspector.Clear();
inspector.Load(currentLayer, oid);
for (int i = 0; i < gridFields.Rows.Count; i++)
{
if (gridFields.Rows.Cells[1].Value != null)
{
insp[gridFields.Rows.Cells[0].Value.ToString()] = gridFields.Rows.Cells[1].Value;
}
}
editOperation.Modify(inspector);
}
}
if (!editOperation.IsEmpty)
{
bool result = editOperation.Execute();
if (!result)
{
// throw an error message
}
}
}); //end of QueuedTask
}
catch
{
}
finally
{
this.Cursor = Cursors.Default;
}
} snippet three - an optimized approach private void btnSave_Click_NoChainOptimized(object sender, EventArgs e)
{
try
{
//Give the user a chance to get out.
if (ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Are you sure you want to update all the selected layers?", "Update Selected Features?", System.Windows.MessageBoxButton.YesNo) == System.Windows.MessageBoxResult.No)
return;
this.Cursor = Cursors.WaitCursor;
QueuedTask.Run(() =>
{
Map map = MapView.Active.Map;
//Create the MAIN edit operation...this will show up on the Undo Stack
var editOperation = new ArcGIS.Desktop.Editing.EditOperation();
editOperation.Name = "Update Multiple Features";
editOperation.EditOperationType = ArcGIS.Desktop.Editing.EditOperationType.Long;
var inspector = new ArcGIS.Desktop.Editing.Attributes.Inspector(true);
//Go through each layer in the Layers listbox
foreach (string layer in lstLayers.Items)
{
var currentLayer = map.FindLayers(layer).FirstOrDefault() as BasicFeatureLayer;
var selection = currentLayer.GetSelection();
IReadOnlyList<long> selectedOIDs = selection.GetObjectIDs();
inspector.Clear();
// load all the selected oids into the inspector
// we can do this because each feature will have the exact same fields updated to the same values
inspector.Load(currentLayer, selectedOIDs);
for (int i = 0; i < gridFields.Rows.Count; i++)
{
if (gridFields.Rows.Cells[1].Value != null)
{
insp[gridFields.Rows.Cells[0].Value.ToString()] = gridFields.Rows.Cells[1].Value;
}
}
// queue the modify
editOperation.Modify(inspector);
}
// finished the layer loop - commit all the edits
if (!editOperation.IsEmpty)
{
bool result = editOperation.Execute();
if (!result)
{
// throw an error message
}
}
}); //end of QueuedTask
}
catch
{
}
finally
{
this.Cursor = Cursors.Default;
}
}
There's a lot of information here. Let me know if you still have questions about edit operations and chaining or if something I've said isn't clear. Narelle
... View more
01-08-2018
07:40 PM
|
3
|
1
|
1171
|
POST
|
Brian, The first thing to check would be the result of the main EditOperation. If this does not succeed then nothing will be placed on the undo/redo stack regardless of the success or failure of the chained operations. In your situation perhaps there is no feature with object id 1 in 'firstLayer' or 'firstLayer' itself could be null. Check the result of the editOperation.Execute line (as I updated below). If this is false then that is the reason why you are not seeing anything on the undo/redo stack. There shouldn't be any issues with running editOperations (chained or otherwise) from forms whether they are WPF or windows forms. Narelle var inspSetup = new ArcGIS.Desktop.Editing.Attributes.Inspector();
inspSetup.Load(firstLayer, 1);
editOperation.Modify(inspSetup);
bool result = editOperation.Execute();
... View more
01-07-2018
04:59 PM
|
0
|
4
|
1171
|
POST
|
Brian, A chained operation must be executed after the principal edit operation. In general the pattern is 1. create edit operation 2. do action(s) (Create, Modify, Cut etc) 3. execute edit operation 4. create chain operation from the edit operation 5. do action(s) on chain operation (Create, Modify, Cut etc) 6. execute chain operation This pattern will add one item to the undo stack (with the name assigned to the edit operation). All actions will be reversed on undo. Narelle
... View more
11-30-2017
10:02 AM
|
0
|
3
|
1220
|
POST
|
Try this, // change this to get the appropriate layer you want var layer = MapView.Active.Map.GetLayersAsFlattenedList().FirstOrDefault(); // select it in the TOC List<Layer> layersToSelect = new List<Layer>(); layersToSelect.Add(layer); MapView.Active.SelectLayers(layersToSelect); // now execute the layer properties command var wrapper = FrameworkApplication.GetPlugInWrapper("esri_mapping_selectedLayerPropertiesButton"); var command = wrapper as ICommand; if (command == null) return; // execute the command if (command.CanExecute(null)) command.Execute(null);
... View more
11-22-2017
01:27 PM
|
2
|
2
|
782
|
Title | Kudos | Posted |
---|---|---|
1 | 08-08-2024 09:44 PM | |
1 | 07-18-2024 04:46 PM | |
1 | 06-04-2024 07:18 PM | |
4 | 05-27-2024 09:22 PM | |
1 | 02-12-2019 08:59 AM |
Online Status |
Offline
|
Date Last Visited |
6 hours ago
|