I would like to create a button that updates the selected feature's attribute. When I started coding, I found that I cannot get the selected feature after I use the default selection tool(the tools under esri_mapping_selectToolPalette). Is it any method to get the selected feature from the default selection tool?
Solved! Go to Solution.
Subscribe to the MapSelectionChangedEvent. Any changes to the map selection via selection tool, via custom selection, etc. will fire the event.
ArcGIS.Desktop.Mapping.Events.MapSelectionChangedEvent.Subscribe((args) => {
//If u are only interested in one particular map...
if (args.Map.Name == "The Map Name I am Interested In") {
System.Diagnostics.Debug.WriteLine("Selection changed");
var sel = args.Selection;//This is what is selected
if (sel.Count == 0) {
System.Diagnostics.Debug.WriteLine(" 0 features selected");
return;
}
//enumerate current selection - a series of keyvalue pairs
//key is the MapMember, Value is the list of OIDs
foreach(var kvp in sel.ToDictionary()) {
var oids = kvp.Value; //OIDs of the selected features
var oid_str_list = oids.Select(oid => oid.ToString()).ToList();
var oid_str = string.Join(",", oid_str_list);
System.Diagnostics.Debug.WriteLine(
$"{kvp.Key.Name}: {oid_str}");
if (kvp.Key is BasicFeatureLayer fl) {
//TODO selection is on a vector layer...
}
else if (kvp.Key is StandaloneTable tbl) {
//TODO selection is on a table...
}
//else if (....)
//{
// etc,etc.
//}
}
}
});
Note: In 2.x, the event argument syntax is slightly different. The Selection property is a Dictionary so there is no sel.ToDictionary() as such.
Subscribe to the MapSelectionChangedEvent. Any changes to the map selection via selection tool, via custom selection, etc. will fire the event.
ArcGIS.Desktop.Mapping.Events.MapSelectionChangedEvent.Subscribe((args) => {
//If u are only interested in one particular map...
if (args.Map.Name == "The Map Name I am Interested In") {
System.Diagnostics.Debug.WriteLine("Selection changed");
var sel = args.Selection;//This is what is selected
if (sel.Count == 0) {
System.Diagnostics.Debug.WriteLine(" 0 features selected");
return;
}
//enumerate current selection - a series of keyvalue pairs
//key is the MapMember, Value is the list of OIDs
foreach(var kvp in sel.ToDictionary()) {
var oids = kvp.Value; //OIDs of the selected features
var oid_str_list = oids.Select(oid => oid.ToString()).ToList();
var oid_str = string.Join(",", oid_str_list);
System.Diagnostics.Debug.WriteLine(
$"{kvp.Key.Name}: {oid_str}");
if (kvp.Key is BasicFeatureLayer fl) {
//TODO selection is on a vector layer...
}
else if (kvp.Key is StandaloneTable tbl) {
//TODO selection is on a table...
}
//else if (....)
//{
// etc,etc.
//}
}
}
});
Note: In 2.x, the event argument syntax is slightly different. The Selection property is a Dictionary so there is no sel.ToDictionary() as such.
Would you mind explaining more about where should these codes go to? Should those codes go to Module1.cs or the button.cs? I am using Arcgis pro 3.0.
The Module is probably the best place. There is an initialize method in the Module which is probably a good spot. I would also set your module autoLoad attribute to true in the Config.daml.
<modules>
<insertModule id="...." className="Module1" autoLoad="true"
caption="Module1">
internal class Module1 : Module {
private static Module1 _this = null;
...
protected override bool Initialize()
{
//TODO subscribe to the mapping event here
return true;
}
Thank you for your solution. Here is what I come up with to fit my situation.
I added the following code in module1.cs like you said. And created a class to store selections so I can access the selected features within my addin project.
protected override bool Initialize()
{
SubscribleMapSelectionChangedEvent();
return base.Initialize();
}
private void SubscribleMapSelectionChangedEvent()
{
ArcGIS.Desktop.Mapping.Events.MapSelectionChangedEvent.Subscribe((args) => {
//If u are only interested in one particular map...
if (args.Map.Name == "My map")
{
#if DEBUG
System.Diagnostics.Debug.WriteLine("Selection changed");
#endif
var sel = args.Selection;//This is what is selected
if (sel.Count == 0)
{
#if DEBUG
System.Diagnostics.Debug.WriteLine(" 0 features selected");
#endif
return;
}
else
{
CommonObject.GlobalVariables.SelectedFeatures = sel.ToDictionary();
}
}
});
}
Nice work Oscar. One thing I thought I would mention: The module class is actually already global throughout the addin (by design). All classes can access it via the special "singleton" property called "Current".
Therefore, if you wanted, you could add a "SelectedFeatures" property to your module class directly and access it that way. So it could look something like this:
internal class Module1 : Module {
...
private Dictionary<MapMember, List<long>> _selFeatures;
//Any (non-private) module property or method can be accessed from
//anywhere within the addin
internal Dictionary<MapMember, List<long>> SelectedFeatures =>
_selFeatures ??= new Dictionary<MapMember, List<long>>();
//elsewhere...access the property via Module1.Current...
foreach(var kvp in Module1.Current.SelectedFeatures) {
Thanks for your additional info, cheers!