Hi,
I'm trying to create an add-in tool to search (with a wildcard preferably) for feature classes or tables in a GDB or an SDE by right clicking on the GDB/SDE with an option Search and list the search result of that GDB/SDE. Once they are listed, add them to the current map when clicked. Than Aung
Thanks.
Solved! Go to Solution.
Hi Mehdi Pira,
Here is the code snippet you can use, all in all
1. you need to retrieve feature class list from geodatabase instance, by calling GetDefinitions<FeatureClassDefinition>(), from there just retrieve the feature class name by calling GetName method and compare one by one.
Firstly lets have a view model to keep those result.
public class CatalogSearchResultFeatureClassInfo : NotifyPropertyBase
{
private string _featureClassName;
public string FeatureClassName
{
get => _featureClassName;
set
{
_featureClassName = value;
OnPropertyChanged();
}
}
private string _dbConnectionPath;
public string DbConnectionPath
{
get => _dbConnectionPath;
set
{
_dbConnectionPath = value;
OnPropertyChanged();
}
}
}
Next lets implement the search function, this assume user need to select fgdb or sde connection item from catalog.
SearchResult shall be the list of CatalogSearchResultFeaureClassInfo.
All in all read the comment of the process.
private async void PerformSearchFeatureClassCommand(object args)
{
//get catalog pane
ArcGIS.Desktop.Core.IProjectWindow currentProjectWindow = Project.GetCatalogPane(true);
//checking
if (currentProjectWindow == null)
{
MessageBox.Show("Please select a geodatabase from catalog");
return;
}
//get the selection
int selectionCount = currentProjectWindow.SelectionCount;
if (selectionCount <= 0)
{
MessageBox.Show("Please select a geodatabase from catalog");
return;
}
this.SelectedConnection = currentProjectWindow.SelectedItems.First();
this._gdbPath = this.SelectedConnection.Path;
Geodatabase geodatabase = null;
Uri gdbPath = new Uri(this._gdbPath);
ProgressorSource ps = new ProgressorSource("Processing search");
//for your output
List<string> outputFeatureclassNameList = new List<string>();
bool process = await QueuedTask.Run(() =>
{
//check gdb or sde connection
//apart from that it is handled by user and the properties need to setup manually
if (gdbPath.AbsoluteUri.EndsWith(".gdb", StringComparison.OrdinalIgnoreCase))
{
geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(gdbPath));
}
else if (gdbPath.AbsoluteUri.EndsWith(".sde", StringComparison.OrdinalIgnoreCase))
{
geodatabase = new Geodatabase(new DatabaseConnectionFile(gdbPath));
}
else
{
return false;
}
if (geodatabase == null)
{
return false;
}
//Now lets search
IReadOnlyList<FeatureClassDefinition> fcd = geodatabase.GetDefinitions<FeatureClassDefinition>();//Get all feature class definition
try
{
List<string> featureclassList = fcd.Select(x => x.GetName()).ToList();
//that enhance case in-sensitive search
outputFeatureclassNameList = featureclassList.Where(fcn=> CultureInfo.CurrentCulture.CompareInfo.IndexOf(fcn, this.SearchInput, CompareOptions.IgnoreCase) >= 0).ToList();
}
catch
{
//no result case
}
return true;
}, ps.Progressor);
if (!process)
{
ProDialog.MessageBox.Show("Please select a geodatabase from catalog");
return;
}
//bind this this.searchResult with your UI, Queue task will give you issue if you modify this in the queue task, so Copy back
this.SearchResult = new List<CatalogSearchResultFeatureClassInfo>();
foreach (string str in outputFeatureclassNameList)
{
this.SearchResult.Add(new CatalogSearchResultFeatureClassInfo()
{
DbConnectionPath = this._gdbPath,
FeatureClassName = str
});
}
}
For the add the result item into map, try and bind the searchresult variable to grid or listbox or something , bind with a variable in your viewmodel let say - variable name as SelectedFC,
You can follow this code => LayerFactory.Instance.CreateLayer(new Uri("your feature class path"), map)
Below is the code snippet, which will be helpful for you.
public async void AddToCurrentMap()
{
var mapView = MapView.Active;
if (mapView != null)
{
try
{
string currentFCPath = Path.Combine(this._gdbPath, this.SelectedFC.FeatureClassName);
var ps = new ProgressorSource("Adding the feature class..");//lets display progress dialog so it look nicer for user, took sometime so lets user sit tight and wait
await QueuedTask.Run(() =>
{
LayerFactory.Instance.CreateLayer(new Uri(currentFCPath), mapView.Map);
}, ps.Progressor);
}
catch (Exception ex)
{
MessageBox.Show("Unable to add feature class into map");
//oops I got error, better log here
}
}
else
{
MessageBox.Show("Please activate a map view to add layer");
return;
}
}
Hi Mehdi Pira,
Here is the code snippet you can use, all in all
1. you need to retrieve feature class list from geodatabase instance, by calling GetDefinitions<FeatureClassDefinition>(), from there just retrieve the feature class name by calling GetName method and compare one by one.
Firstly lets have a view model to keep those result.
public class CatalogSearchResultFeatureClassInfo : NotifyPropertyBase
{
private string _featureClassName;
public string FeatureClassName
{
get => _featureClassName;
set
{
_featureClassName = value;
OnPropertyChanged();
}
}
private string _dbConnectionPath;
public string DbConnectionPath
{
get => _dbConnectionPath;
set
{
_dbConnectionPath = value;
OnPropertyChanged();
}
}
}
Next lets implement the search function, this assume user need to select fgdb or sde connection item from catalog.
SearchResult shall be the list of CatalogSearchResultFeaureClassInfo.
All in all read the comment of the process.
private async void PerformSearchFeatureClassCommand(object args)
{
//get catalog pane
ArcGIS.Desktop.Core.IProjectWindow currentProjectWindow = Project.GetCatalogPane(true);
//checking
if (currentProjectWindow == null)
{
MessageBox.Show("Please select a geodatabase from catalog");
return;
}
//get the selection
int selectionCount = currentProjectWindow.SelectionCount;
if (selectionCount <= 0)
{
MessageBox.Show("Please select a geodatabase from catalog");
return;
}
this.SelectedConnection = currentProjectWindow.SelectedItems.First();
this._gdbPath = this.SelectedConnection.Path;
Geodatabase geodatabase = null;
Uri gdbPath = new Uri(this._gdbPath);
ProgressorSource ps = new ProgressorSource("Processing search");
//for your output
List<string> outputFeatureclassNameList = new List<string>();
bool process = await QueuedTask.Run(() =>
{
//check gdb or sde connection
//apart from that it is handled by user and the properties need to setup manually
if (gdbPath.AbsoluteUri.EndsWith(".gdb", StringComparison.OrdinalIgnoreCase))
{
geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(gdbPath));
}
else if (gdbPath.AbsoluteUri.EndsWith(".sde", StringComparison.OrdinalIgnoreCase))
{
geodatabase = new Geodatabase(new DatabaseConnectionFile(gdbPath));
}
else
{
return false;
}
if (geodatabase == null)
{
return false;
}
//Now lets search
IReadOnlyList<FeatureClassDefinition> fcd = geodatabase.GetDefinitions<FeatureClassDefinition>();//Get all feature class definition
try
{
List<string> featureclassList = fcd.Select(x => x.GetName()).ToList();
//that enhance case in-sensitive search
outputFeatureclassNameList = featureclassList.Where(fcn=> CultureInfo.CurrentCulture.CompareInfo.IndexOf(fcn, this.SearchInput, CompareOptions.IgnoreCase) >= 0).ToList();
}
catch
{
//no result case
}
return true;
}, ps.Progressor);
if (!process)
{
ProDialog.MessageBox.Show("Please select a geodatabase from catalog");
return;
}
//bind this this.searchResult with your UI, Queue task will give you issue if you modify this in the queue task, so Copy back
this.SearchResult = new List<CatalogSearchResultFeatureClassInfo>();
foreach (string str in outputFeatureclassNameList)
{
this.SearchResult.Add(new CatalogSearchResultFeatureClassInfo()
{
DbConnectionPath = this._gdbPath,
FeatureClassName = str
});
}
}
For the add the result item into map, try and bind the searchresult variable to grid or listbox or something , bind with a variable in your viewmodel let say - variable name as SelectedFC,
You can follow this code => LayerFactory.Instance.CreateLayer(new Uri("your feature class path"), map)
Below is the code snippet, which will be helpful for you.
public async void AddToCurrentMap()
{
var mapView = MapView.Active;
if (mapView != null)
{
try
{
string currentFCPath = Path.Combine(this._gdbPath, this.SelectedFC.FeatureClassName);
var ps = new ProgressorSource("Adding the feature class..");//lets display progress dialog so it look nicer for user, took sometime so lets user sit tight and wait
await QueuedTask.Run(() =>
{
LayerFactory.Instance.CreateLayer(new Uri(currentFCPath), mapView.Map);
}, ps.Progressor);
}
catch (Exception ex)
{
MessageBox.Show("Unable to add feature class into map");
//oops I got error, better log here
}
}
else
{
MessageBox.Show("Please activate a map view to add layer");
return;
}
}
Brilliant! That's what I was looking for.
Thanks indeed Than Aung