ProConcepts Content and Items - Esri/arcgis-pro-sdk GitHub Wiki
This ProConcepts will cover content in Pro, its usage, and relevant API functionality.
Language: C#
Subject: Content
Contributor: ArcGIS Pro SDK Team <[email protected]>
Organization: Esri, http://www.esri.com
Date: 10/06/2024
ArcGIS Pro: 3.4
Visual Studio: 2022
In this topic
- Overview
- Project Content
- Application Options
- Portal Content
- External Content
- ItemFactory and AddItem
- ItemFactory and Import
- Items and Factories
- Refresh items
- Getting Item Content
- Item Metadata
- Catalog Context
- Detecting Project Changes
- Favorites
- Browse Dialog Filters
- UI Controls
In Pro, content is represented as Items. There are two categories of Items:
- Content that is stored in, or referenced by, the Project document. This content, is referred to as project content (or project "items")* and includes maps, layouts, styles, toolboxes, folders, etc.
- Content that is browsed by Pro and is external to the project. Content can be browsed from folders, portal and online, geodatabases, and toolboxes and includes text files, xml files, folders, database connection files, layer files, task files, mxds, sxds, etc. This content, is referred to as external content (or external "items").
A complete list of the supported data types and items for Pro can be found here
*Content can also be included within Favorites at 2.0.
Project content, or project "items", lives within the project. At some point in time, project content was either added or imported into the project from an external source or was created (and saved) in a Pro session. Once in a project, content can packaged and shared (see Project Package)
In the API, project "items" all include the suffix ProjectItem
in their class name and derive from ArcGIS.Desktop.Core.Item
(by way of a couple of internal classes not relevant to the public API). Project item classes implement the interface IProjectItem
, topic 15851, which is the required parameter type for adding and removing content to and from Pro: Project.Current.AddItem(IProjectItem item)
, topic 15947, and Project.Current.RemoveItem(IProjectItem item)
, topic 15951. Adding content to the project is discussed in detail in ItemFactory and AddItem.
The public API currently provides the following project items:
https://pro.arcgis.com/en/pro-app/latest/sdk/api-reference/.html
Class | Namespace | Assembly |
---|---|---|
BusinessAnalystProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
FolderConnectionProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
GDBProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
HuffModelProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
LocatorsConnectionProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
SegmentationProfileProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
SegmentationProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
SegmentationTargetGroupProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
ServerConnectionProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
StatisticalDataCollectionProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
VariableListProjectItem | ArcGIS.Desktop.Catalog | ArcGIS.Desktop.Catalog.dll |
ReviewerBatchJobProjectItem | ArcGIS.Desktop.DataReviewer | ArcGIS.Desktop.DataReviewer.dll |
ReviewerResultsProjectItem | ArcGIS.Desktop.DataReviewer | ArcGIS.Desktop.DataReviewer.dll |
GeoprocessingProjectItem | ArcGIS.Desktop.GeoProcessing | ArcGIS.Desktop.GeoProcessing.dll |
SAModelsProjectItem | ArcGIS.Desktop.GeoProcessing | ArcGIS.Desktop.GeoProcessing.dll |
LayoutProjectItem | ArcGIS.Desktop.Layouts | ArcGIS.Desktop.Layouts.dll |
ReportProjectItem | ArcGIS.Desktop.Layouts | ArcGIS.Desktop.Layouts.dll |
MapProjectItem | ArcGIS.Desktop.Mapping | ArcGIS.Desktop.Mapping.dll |
StyleProjectItem | ArcGIS.Desktop.Mapping | ArcGIS.Desktop.Mapping.dll |
TaskProjectItem | ArcGIS.Desktop.TaskAssistant | ArcGIS.Desktop.TaskAssistant.dll |
Application units in Pro are represented by the ArcGIS.Desktop.Core.UnitFormats.DisplayUnitFormat
class. The class contains both a measurement unit, displayUnitFormat.MeasurementUnit
, for calculating measurements and a displayUnitFormat.UnitFormatType
which controls how unit values are formatted. A DisplayUnitFormat can have one of 8 different UnitFormatTypes matching the same organization of units into 8 sub categories as on the Project options "units" dialog. The first five unit unit formats are geographic measures that are used to describe locations on the earth, while the last three are page and symbol measures that refer to the placement of objects on a page:
- UnitFormatType.Distance: Distance units specify distances between locations.
- UnitFormatType.Angular: Angular units specify distances on a sphere or spheroid.
- UnitFormatType.Area: Area units measure the size of two-dimensional planes.
- UnitFormatType.Location: Location units describe an absolute geographic location in x,y format. They are related to the coordinate system of the project.
- UnitFormatType.Direction: Direction units reference a meridian to describe the spatial relationship between a direction and a reference axis.
- UnitFormatType.Page: Page units, usually millimeters or inches, are used to arrange map elements on a layout page for printing.*
- UnitFormatType.Symbol2D: Symbol2D units are used to render dimensions of shapes, distance tolerances, and offsets both on a computer screen and on a printed map.*
- UnitFormatType.Symbol3D: Symbol3D units are used to render dimensions of shapes, distance tolerances, and offsets for three-dimensional symbols.**
The list of available units of a given UnitFormatType, currently available in the current project, can be accessed via DisplayUnitFormats.Instance.GetProjectUnitFormats(unit_type)
and the full list of all possible units, whether available in the current project or not, is accessed off DisplayUnitFormats.Instance.GetPredefinedProjectUnitFormats(unit_type)
. The returned collections correspond to the list of units shown on the Project options unit dialog and the full list of units associated with each unit type, also on the Project options dialog, respectively.
*The list of available units is fixed and cannot be changed.
**The list of available Symbol3D units corresponds to the list of available UnitFormatType.Distance units. Changes made to the list of distance units automatically appear in the list of 3D symbol display unit formats.
Project unit format collections can always be accessed, even when a project is not open, however, changes made to the different collections of project unit formats can only be persisted if a project is currently open.
In this example, both the full list of all available units and current list of units in the project, is retrieved (for all UnitFormatTypes) from the DisplayUnitFormats singleton instance:
QueuedTask.Run(() => {
var unit_formats = Enum.GetValues(typeof(UnitFormatType)).OfType<UnitFormatType>().ToList();
//The full list of unit formats
System.Diagnostics.Debug.WriteLine("Full list\r\n");
foreach(var unit_type in unit_formats) {
System.Diagnostics.Debug.WriteLine($"Format: {unit_type.ToString()}");
var units = DisplayUnitFormats.Instance.GetPredefinedProjectUnitFormats(unit_type);
foreach(var unit in units) {
var line = $"{unit.DisplayName}, {unit.UnitName}, {unit.UnitCode}:: {unit.MeasurementUnit.Name}";
System.Diagnostics.Debug.WriteLine(line);
}
}
System.Diagnostics.Debug.WriteLine("\r\nProject list\r\n");
foreach(var unit_type in unit_formats) {
System.Diagnostics.Debug.WriteLine($"Format: {unit_type.ToString()}");
var units = DisplayUnitFormats.Instance.GetProjectUnitFormats(unit_type);
foreach(var unit in units) {
var line = $"{unit.DisplayName}, {unit.UnitName}, {unit.UnitCode}:: {unit.MeasurementUnit.Name}";
System.Diagnostics.Debug.WriteLine(line);
}
}
...
The list of which unit format choices are available for the current project can be updated via SetProjectUnitFormats(replacement_list, replacement_default)
where "replacement_default" can be null. This is a complete replacement (not an add or update). Whatever entries are in the replacement list are set as the new list of available choices (accessed off the GetProjectUnitFormats(...)
method). If a replacement default unit format is not specified (i.e. the replacement default parameter is null) then the existing default unit is retained. The entries in the "replacement list" must all be of the same UnitFormatType or an ArgumentException will be thrown. Attempting to change the list of units for Page, Symbol2D, and Symbol3D* will throw an InvalidOperationException.
//Must be on the QueuedTask.Run()
//Get the full list of distance units
var all_units = DisplayUnitFormats.Instance.GetPredefinedProjectUnitFormats(UnitFormatType.Distance);
//keep units with an even factory code
var list_units = all_units.Where(du => du.UnitCode % 2 == 0).ToList();
//set them as the new distance unit collection. A new default is not being specified...
DisplayUnitFormats.Instance.SetProjectUnitFormats(list_units);
*Recall that the list of units for Page and Symbol2D are fixed and the list of available UnitFormatType.Symbol3D units is changed via the list of UnitFormatType.Distance units.
The currently selected default unit format for the given UnitFormatType can be accessed via DisplayUnitFormats.Instance.GetDefaultProjectUnitFormat(unit_type)
and can be changed via DisplayUnitFormats.Instance.SetDefaultProjectUnitFormat(displayFormatUnit)
. If a project is not currently open when SetDefaultProjectUnitFormat(...) is called, the change will be ignored. In this example, the list of current project default format units is retrieved and the default of each list is set to the last entry in each respective list (whether it is the current default or not):
QueuedTask.Run(() => {
var unit_formats = Enum.GetValues(typeof(UnitFormatType)).OfType<UnitFormatType>().ToList();
foreach(var unit_type in unit_formats) {
var current_default = DisplayUnitFormats.Instance.GetDefaultProjectUnitFormat(unit_type);
//Arbitrarily pick the last unit in each unit format list
var replacement = DisplayUnitFormats.Instance.GetProjectUnitFormats(unit_type).Last();
DisplayUnitFormats.Instance.SetDefaultProjectUnitFormat(replacement);
var line = $"{current_default.DisplayName}, {current_default.UnitName}, {current_default.UnitCode}";
var line2 = $"{replacement.DisplayName}, {replacement.UnitName}, {replacement.UnitCode}";
System.Diagnostics.Debug.WriteLine($"Format: {unit_type.ToString()}");
System.Diagnostics.Debug.WriteLine($" Current default: {line}");
System.Diagnostics.Debug.WriteLine($" Replacement default: {line2}");
}
Changes can be made to individual DisplayUnitFormat instances to customize their properties (such as name, display name, abbreviation, and format parameters) Changes made to individual DisplayUnitFormat instances must be applied back to the project unit format collection, via SetProjectUnitFormats(...)
, in order for them to be persisted. The exception is the default format unit. In this case, just the default unit can be updated by passing in an updated DisplayUnitFormat instance to the SetDefaultProjectUnitFormat(...)
method. Changes made to any of the list of units or to individual units themselves are persisted by saving the current project otherwise the changes will be lost when the project is closed. Changes made to DisplayUnitFormats are limited to just the project, or projects, within which changes are made.
In this example, the unit's abbreviation is appended to the end of each unit's display name in the list of UnitFormatType.Angular unit types and then applied back to the current project:
QueuedTask.Run(() => {
var angle_units = DisplayUnitFormats.Instance.GetProjectUnitFormats(UnitFormatType.Angular);
//Edit the display name of each unit
foreach(var unit in angle_units) {
unit.DisplayName = $"{unit.DisplayName} ({unit.Abbreviation})";
}
//apply the units and set the default to be the first entry
DisplayUnitFormats.Instance.SetProjectUnitFormats(angle_units, angle_units.First());
//The project must be saved to persist the changes...
...
Addins interested in changes to the project units should subscribe to the ArcGIS.Desktop.Core.Events.ProjectUnitFormatsChangedEvent
event. Any change to the lists of project units fires this event (whether changes were made to the Project unit format lists, defaults, or to display unit format properties). The ProjectUnitFormatsChangedEventArgs instance contains a ProjectUnitFormatsChangedEventArgs.DefaultsChangedHint
property with a list of the UnitFormatTypes for those default values that were changed.
Note that the DefaultsChangedHint will always contain a list of all UnitFormatTypes if any change was made to the units via the Project options units dialog. All current default units for the project get overrwritten on an 'Ok' triggering an event with all UnitFormatTypes added to the DefaultsChangedHint collection. Only if an add-in makes a specific change to a project unit default will the DefaultsChangedHint contain just the specific UnitFormatType (or Types) whose default(s) were changed.
ArcGIS.Desktop.Core.Events.ProjectUnitFormatsChangedEvent.Subscribe((args) => {
//A change was made to the project units via an add-in or from the Pro UI
//Check the hint - NOte: DefaultsChangedHint will contain all 8 UnitFormatTypes if the event
//was triggered by an update off the Project options unit dialog
foreach (var hint in args.DefaultsChangedHint) {
//TODO - use the event hint as needed
}
...
});
A subset of Pro application options are available via the ArcGIS.Desktop.Core.ApplicationOptions
class. Available options in the API are organized via a series of "options" categories , or classes, accessed as static properties off ApplicationOptions which loosely correspond to the same organization (of options) on the Pro application "Options" dialog (accessed via the Pro backstage). ApplicationOptions was introduced at 2.9 and has been extended over subsequent releases. The following options categories/classes are available in the current release:
///<summary>Available Pro application backstage options</summary>
public static class ApplicationOptions {
///<summary>Gets the available application general options</summary>
public static GeneralOptions GeneralOptions { get; }
///<summary>Gets the available application display options</summary>
public static DisplayOptions DisplayOptions { get; }
///<summary>Gets the available application navigation options</summary>
public static NavigationOptions NavigationOptions { get; }
///<summary>Gets the application download options</summary>
public static DownloadOptions DownloadOptions { get; }
///<summary>Gets the available application geoprocessing options</summary>
public static GeoprocessingOptions GeoprocessingOptions { get; }
///<summary>Gets the application mapping options</summary>
public static MappingOptions MappingOptions { get; }
///<summary>Gets the application selection options</summary>
public static SelectionOptions SelectionOptions { get; }
///<summary>Gets the application layout options</summary>
public static LayoutOptions LayoutOptions { get; }
///<summary>Gets the application report options</summary>
public static ReportOptions ReportOptions { get; }
///<summary>Gets the application text and graphics elements options</summary>
public static TextAndGraphicsElementsOptions TextAndGraphicsElementsOptions { get; }
///<summary>Gets the application editing options</summary>
public static EditingOptions EditingOptions { get; }
///<summary>Gets the application table options</summary>
public static TableOptions TableOptions { get; }
///<summary>Gets the application versioning options</summary>
public static VersioningOptions VersioningOptions { get; }
///<summary>Gets the application raster and imagery options</summary>
public static RasterImageryOptions RasterImageryOptions { get; }
///<summary>Gets the application exploratory analysis options</summary>
public static ExploratoryAnalysisOptions ExploratoryAnalysisOptions { get; }
}
The pattern of usage is the same for each given option category/class and follows the same behavior implemented on the Pro options UI. The available application settings (in each option category), correspond to individual "get" and "set" properties which are accessed off their respective, parent static option category class (which are, in turn, accessed from ApplicationOptions
). Any change to a given setting is applied immediately, without a separate commit or save action. Properties set via the API are not undoable. To revert a property back to its previous value, you must execute another "set" to whichever is the desired value. Certain properties may implement internal validation logic to ensure that the value being "applied" or "set" is valid for the given setting. In most cases, attempting to set an invalid property value will be ignored.
*In some cases, a "Get" and "Set" method, rather than a property, may be provided. This is especially true when a particular setting can only be accessed and manipulated via the Pro Main CIM Thread, MCT (which requires a QueuedTask.Run
).
At 3.1, functionality was introduced to ArcGIS Pro to allow system administrators to deploy the application across a team or an organization and control a number of settings on behalf of their users. Administrators can set default values for a select number of settings. They can also lock these settings so that users cannot change them from the value set by the administrator. Developers should note that if a particular setting is locked, then changing the value of the associated property via the ApplicationOptions category/class API is ignored.
In the following example, the add-in is accessing and setting ApplicationOptions.GeneralOptions
for startup, geodatabase, and toolbox options:
//access the current values
var startMode = ApplicationOptions.GeneralOptions.StartupOption;
var aprx_path = ApplicationOptions.GeneralOptions.StartupProjectPath;
var gdb_option = ApplicationOptions.GeneralOptions.DefaultGeodatabaseOption;
var def_gdb = ApplicationOptions.GeneralOptions.CustomDefaultGeodatabase;//can be null
var tbx_option = ApplicationOptions.GeneralOptions.DefaultToolboxOption;
var def_tbx = ApplicationOptions.GeneralOptions.CustomDefaultToolbox;//can be null
//Set the application to use a custom project, gdb, and toolbox
//In each case, the custom _path_ must be set _first_ before setting the "option"
ApplicationOptions.GeneralOptions.StartupProjectPath = @"E:\data\usa.aprx";//custom project path first
ApplicationOptions.GeneralOptions.StartupOption = StartProjectMode.WithDefaultProject;//option to use it second
ApplicationOptions.GeneralOptions.CustomDefaultGeodatabase = @"E:\data\usa.gdb";//custom gdb path first
ApplicationOptions.GeneralOptions.DefaultGeodatabaseOption = OptionSetting.UseCustom;//option to use it second
ApplicationOptions.GeneralOptions.CustomDefaultToolbox = @"E:\data\usa.tbx";//custom toolbox path first
ApplicationOptions.GeneralOptions.DefaultToolboxOption = OptionSetting.UseCustom;//option to use it second
//To set the paths back to _null_ (the default), the options must be set _back_ to
//their default value _first_ (i.e. reverse of the order used to set the custom path
//in the first place)
ApplicationOptions.GeneralOptions.StartupOption = StartProjectMode.ShowStartPage;//set default option first
ApplicationOptions.GeneralOptions.StartupProjectPath = null;//path back to null second*
ApplicationOptions.GeneralOptions.DefaultGeodatabaseOption = OptionSetting.UseDefault;//set default option first
ApplicationOptions.GeneralOptions.CustomDefaultGeodatabase = null;//path back to null second*
ApplicationOptions.GeneralOptions.DefaultToolboxOption = OptionSetting.UseDefault;//set default option first
ApplicationOptions.GeneralOptions.CustomDefaultToolbox = null;//path back to null second*
//nulling out the path isn't actually necessary to switch back to the default behavior. It is done really for
//completeness. If the option setting is set to use "default", then any custom path that may (still) be stored
//in the companion project, gdb, toolbox path property will be ignored. However, the path(s) will be visible on
//the General options UI.
In this example, the add-in is accessing and setting ApplicationOptions.TextAndGraphicsElementsOptions
for default font, default point, line, and polygon symbols:
//Note: QueuedTask required...
QueuedTask.Run(()=> {
//First, access the existing defaults for font, point, line, poly
var def_font = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultFont();//returns a tuple
System.Diagnostics.Debug.WriteLine($"default font: {def_font.fontName}, {def_font.styleName}");
//Current symbol defaults
var ptSymbol = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultPointSymbol();
var lineSymbol = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultLineSymbol();
var polySymbol = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultPolygonSymbol();
var textSymbol = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultTextSymbol();
//Now set some new defaults
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultFont("tahoma");
//...or with a style as well
//ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultFont("tahoma", "bold");
var ptSymbol2 = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.RedRGB, 14, SimpleMarkerStyle.Diamond);
var lineSymbol2 = SymbolFactory.Instance.ConstructLineSymbol(
ColorFactory.Instance.RedRGB, 2, SimpleLineStyle.Dash);
var polySymbol2 = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.RedRGB, SimpleFillStyle.DiagonalCross);
var textSymbol2 = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.RedRGB, 12);
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultPointSymbol(ptSymbol2);
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultLineSymbol(lineSymbol2);
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultPolygonSymbol(polySymbol2);
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultTextSymbol(textSymbol2);
});
Download options control where content being downloaded from online or staged for uploading to online is located. Download options also control the various different locations for unpacking Pro content and for writing ofline map content. Individual download option settings are organized into the same "groupings" of settings as are available on the Pro "Sharing and Download" options UI. In many cases, such "groupings" of settings are mutually exclusive meaning that settingone property "true" in the api will set the other "related" property/properties to false. This is consistent with the operation of the Pro options UI.
For example, take the Unpacking settings for "Other Packages and Files". There are three:
- An "Unpack to this location" setting corresponding to
ApplicationOptions.DownloadOptions.UnpackOtherLocation
. - An "Ask where to save before unpacking" setting corresponding to
ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation
. - An "Unpack to the project's home folder" setting corresponding to
ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation
.
On the UI, toggling any of the three radio buttons for these settings "on" sets the other two to false. Note however, that if the "Unpack to this location" is set false, the path value is not cleared. The ApplicationOptions.DownloadOptions exhibits the same behavior. Setting either of AskForUnpackOtherLocation or UnpackOtherToProjectLocation to true does not clear the value from UnpackOtherLocation in the api but it will be ignored/overridden. To set the application download options to "Unpack to this location", either explicitly set a path value in UnpackOtherLocation or set both AskForUnpackOtherLocation and UnpackOtherToProjectLocation to false.
//UnpackOther settings control unpacking of anything _other than_
//a ppkx or aptx. Options are mutually exclusive.
//Set ApplicationOptions.DownloadOptions.UnpackOtherLocation explicitly to
//toggle ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation and
//ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation to false
//Note: default is typically <My Documents>\ArcGIS\Packages _not_ null.
//This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.UnpackOtherLocation = @"D:\data\for_other";
//or...to use a location already stored in UnpackOtherLocation as the
//default without changing it,
//set ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation and
//ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation to false
//explicitly. This is equivalent to toggling "on" the 'Unpack to this location' setting.
if (!string.IsNullOrEmpty(ApplicationOptions.DownloadOptions.UnpackOtherLocation)) {
ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation = false;
ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation = false;
}
//Setting ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation to
//true overrides any UnpackOtherLocation value and sets
//ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation to false.
//This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation = true;
//Setting ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation to
//true overrides any UnpackOtherLocation value and sets
//ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation to false.
//This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation = true;
Unpacking and Offline Maps settings work in a similar fashion.
Portal content is any content that is retrieved from a portal or online. In the Pro UI, portal content shows up in the catalog pane on the "Portal" tab (and in a Catalog view with "Portal" selected in the breadcrumb\text box). Portal content, in the Pro API, is organized into 3 types*:
- Items
- Folders
- Groups
Portal content derives from ArcGIS.Desktop.Core.Portal.OnlineItem
topic 18241, which, in turn, derives from ArcGIS.Desktop.Core.Item
topic 9109, the base class for all content in Pro. Note: the ArcGIS.Desktop.Core.Portal
namespace is in both the ArcGIS.Desktop.Core.dll and the ArcGIS.Desktop.Catalog.dll assemblies.
*Use portal.GetSignOnUsername
to get portal user information and portal.GetPortalInfoAsync
to get the logged on user (or anonymous) view of a portal topic 19170.
Of the 3 types in the API, "Items" are the primary content item and represent over 100 different content types that are currently supported by portal such as web maps, feature services, packages, styles, Microsoft office document files, images, mxds, add-ins, and so on (see supported data types and items and PortalItemType enumeration for the complete list of "item" content types). Items are represented by the ArcGIS.Desktop.Core.Portal.PortalItem
class topic 18175. Because PortalItem "is a" Item, it can be passed as the parameter to any of the class factories that consume items (eg MapFactory or LayerFactory) assuming that the provided item represents content of the correct type. Portal items can be retrieved either by a portal.GetUserContentAsync
call or via a search using portal.SearchForContentAsync
.
var portal = ArcGISPortalManager.Current.GetActivePortal();
var owner = portal.GetSignOnUsername();
//get the user content
var userContent = await portal.GetUserContentAsync(owner);
//folders...
foreach (var pf in userContent.PortalFolders) {
...
//items
foreach (var pi in userContent.PortalItems) {
...
Execute a query to retrieve all web maps visible to the user, within his or her organization:
//assume signed on user is a member of an organization...
//get the organization id
var portalInfo = await portal.GetPortalInfoAsync();
var orgid = portalInfo.OrganizationId;
var query = PortalQueryParameters.CreateForItemsOfType(PortalItemType.WebMap);
query.Limit = 100;
query.OrganizationId = orgid;
//query the organization for web maps...
PortalQueryResultSet<PortalItem> results = await portal.SearchForContentAsync(query);
//create a map (in Pro) from the first item
var result = results.Results.First();
QueuedTask.Run(() => {
if (MapFactory.Instance.CanCreateMapFrom(result))
MapFactory.Instance.CreateMapFromItem(result);
...
Portal items that represent file types such as packages, documents, style files, images, etc. can be downloaded to disk via the portalItem.GetItemDataAsync
method. This retrieves the original item that (was uploaded) from portal and streams it to the file name you provide, on disk, as the parameter to GetItemDataAsync. Portal items that have no downloadable content will write out an empty file.
//assume we query for some content
var results = await portal.SearchForContentAsync(query);
var portalItem = results.Results.First();//first item
var folder = @"E:\Temp\Download\";
var path = System.IO.Path.Combine(folder, portalItem.Name);
//download the item
await portalItem.GetItemDataAsync(path);
Users can organize their portal or online content into folders. Folders are represented by the ArcGIS.Desktop.Core.Portal.PortalFolder
class topic 18157 and can be retrieved via a portal.GetUserContentAsync
method call (which can return all of a user's content including their folders and items). The corollary for portal.GetUserContentAsync
in the Pro UI is the content retrieved for the "My Content" tab in either of the catalog pane or a catalog view.
QueuedTask.Run(() => {
//Retrieve all the portal folders for the active user
var portal = ArcGISPortalManager.Current.GetActivePortal();
var owner = portal.GetSignOnUsername();
//get the user content
var userContent = await portal.GetUserContentAsync(owner);
//folders...
foreach (var pf in userContent.PortalFolders) {
...
Users can also participate in groups. Groups are represented by the ArcGIS.Desktop.Core.Portal.PortalGroup
class topic 18157 and those groups visible to a particular portal user can be retrieved via a portal.GetGroupsFromUserAsync
method call. This corresponds to the content retrieved via the "Groups" tab in the catalog pane or view.
QueuedTask.Run(() => {
//Retrieve all the groups visible to the current signed on user
var owner = portal.GetSignOnUsername();
var groups = await portal.GetGroupsFromUserAsync(owner);
foreach (var group in groups) {
...
Any content that can be browsed (and can be indexed by Pro for browsing) is considered "external content". External content items derive from ArcGIS.Desktop.Core.Item
same as project content items. External content items represent the many different file types or folder types (images, text files, file geodatabase folder, style files, zip archives, etc.) that can exist online or on a physical disk drive whether it can be added to Pro or not. For example, when enumerating the contents of a folder, items are returned for all the content, not just the Pro specific content.
Note: The majority of the external content types derive from Item via "Desktop.Internal" classes (as do project items)*. This is an implementation detail not relevant to the public API. Simply treat them as "Items" in your code because that is what they are. The underlying "Desktop.Internal" classes provide Catalog the functionality it needs to show special icons, customize context menus, provide browsing support (for containers) and that sort of thing.
*Some items are instantiated as "ProjectItem" classes directly by ItemFactory.Instance.Create. These are covered in the next section.
Creating and adding content to a project is a three step process:
-
Create a content item using
ItemFactory.Instance.Create
using the path or url to the content (whether on disk or online). -
Test the returned content for
IProjectItem
* to see if it can be added to the project. -
If it implements IProjectItem, add the content to the project via
Project.Current.AddItem
. AddItem returns true if the item was successfully added.
Internally, the process of "adding" ensures the item is stored within the correct container (Maps for Maps, Layouts for Layouts, Toolboxes for Toolboxes, etc.) and is added to the internal project repository. Note: Project.Current.AddItem must be called within a QueuedTask lambda.
This example creates a layer file item and tests it to see if it can be added to the Project. (The test will fail and show the message box - layer files can only be added to maps (with LayerFactory) - not projects)
//test to see if a layer file can be added
string path = @"E:\Pro\USA\Us_States.lyrx";
Item item = ItemFactory.Instance.Create(path, ItemFactory.ItemType.PathItem);
if (item is IProjectItem)
QueuedTask.Run(() => Project.Current.AddItem((IProjectItem)item));
else
//A layer file can NOT be added to a project. It can only be added to a map
MessageBox.Show($"{item.Path} cannot be added to a project", "Content");
*If you already know that an item is an IProjectItem (e.g. experience, familiarity, snippet, etc.) skip #2 and simply cast the returned item from ItemFactory Create directly. In this example, we know a folder connection is a IProjectItem:
//Add a folder connection
string path = @"E:\Pro";
//Cast item to IProjectItem directly
var folderItem = ItemFactory.Instance.Create(path) as IProjectItem;
//Add it
QueuedTask.Run(() => Project.Current.AddItem(folderItem));
Calls to ItemFactory.Instance.Create
create the project item directly in the following cases:
- FolderConnectionProjectItem (e.g. folders)
- GDBProjectItem (e.g. .gdb, .sde files)
- GeoprocessingProjectItem (e.g. .tbx, .gpkx, .pyt files)
- LocatorsConnectionProjectItem (e.g. .loc files)
- ServerConnectionProjectItem (e.g. .ags, .wcs, .wms, .wfs, .wmts files)
- TaskProjectItem (e.g. task files)
However, these content items still have to be added to the project with AddItem. For example:
//These are equivalent workflows
string folderPath = "@C:\\myDataFolder";
//Get an IProjectItem for the folder
var folderItem = ItemFactory.Instance.Create(path) as IProjectItem;
//Or, get a FolderConnectionProjectItem for the folder
var folderItem = ItemFactory.Instance.Create(path) as FolderConnectionProjectItem;
-- MUST call Project.Current.AddItem if you want to add it! --
Certain file types are silently imported when they are added to a project such as map packages or 10x formatted files (mxds, sxds, styles, etc.) that require conversion. External content types that support importing via the API implement ArcGIS.Desktop.Core.IProjectMultiItem
(refer to topic 15858) and can be passed to Project.Current.ImportItem
to "add" the content to the project as well using the standard Project.Current.AddItem
call. Generally, all 10x file formats that can be imported to Pro support IProjectMultiItem as well as map packages and server connection files.
Using either of Project.Current.ImportItem
or Project.Current.AddItem
with a IProjectMultiItem adds the content to the project*. However, in those cases where more than one item may be created in the project, ImportItem returns the enumeration directly whereas AddItem does not. The canonical case being an mxd that contains both a map and a layout will create two items in the project when it is added.
*Internally, AddItem calls ImportItem for any IProjectMultiItems to perform the "add". Use the overloaded option of ImportItem to add the map or layout to the project without opening a default pane to display it (refer to ImportItem topic22150.html)
For example, either of these workflows can be used to import an mxd into Pro:
string mxd = @"E:\Pro\USA\OceanBasemap.mxd";
//Either...
var addItem = ItemFactory.Instance.Create(mxd, ItemFactory.ItemType.PathItem) as IProjectItem;
await QueuedTask.Run(() => Project.Current.AddItem(addItem));
//Or...
var importItem = ItemFactory.Instance.Create(mxd, ItemFactory.ItemType.PathItem) as IProjectMultiItem;
var items = await QueuedTask.Run(() => Project.Current.ImportItem(importItem));
//and also Project.Current.ImportItem(importItem, false) to import and ~not~ open a pane
//And, of course, MapFactory.Instance.CreateMapFromItem.... not shown
To check whether an item can use Project.Current.ImportItem, test for the presence of the IProjectMultiItem interface:
var item = ItemFactory.Instance.Create(itemPath, ItemFactory.ItemType.PathItem);
//Can it be imported?
if (item is IProjectMultiItem) {
//yes it can
}
//Can it be added?
else if (item is IProjectItem) {
//yes it can
}
For importing Layouts, the ImportItem(IProjectMultiItem item, bool openPaneAfterImport, bool useExistingMaps = false)
overload provides a third parameter - useExistingMaps
. Set this to true to connect any existing maps in the project to the relevant map frame content on the imported layout. By default, importing a layout file copies all of the maps referenced by the layout. However, if the maps already exist in the project, setting useExistingMaps =true only copies maps that don't exist in the project, and reuses those that do (exist on the imported layout). This avoids duplicating maps in the project.
The following factories provide "create" methods that consume Items:
- ArcGIS.Desktop.Mapping.MapFactory
- ArcGIS.Desktop.Mapping.LayerFactory
- ArcGIS.Desktop.Mapping.StandaloneTableFactory
This is useful if you are adding layer files or feature classes (as standalone tables) to a map or maps to a project and have already retrieved an item to the external content at some earlier point in your workflow (e.g. you retrieved a layer file item from a browse of a folder connection). For example:
//Use the MapFactory to create a map from an external item (e.g. a mapx file or and mxd)
Item mapItem = ... //retrieved earlier from ItemFactory or from browsing a folder...
return QueuedTask.Run(() => {
// verify that a map can be created from the item
if (MapFactory.Instance.CanCreateMapFrom(mapItem)) {
// creates a new map and adds it to the project. Also opens the mapview
MapFactory.Instance.CreateMapFromItem(mapItem);
}
});
Of course, you can also use overloads on LayerFactory and StandaloneTableFactory that take the physical path ("Uri") to the content without creating an item first
To refresh a parent item's child item collection, item.Refresh() can be called. Usually this shouldn't be necessary, however certain items can get out of sync with their child item collection. For example, between the time when new child items may be added on disk external to Pro and the parent folder item updates its child item cache.
When refreshing items, certain items can only be refreshed on the Main CIM Thread, MCT, via QueuedTask.Run whereas others can be refreshed on any thread, to include the UI. To determine if the MCT is required for an item refresh, item.IsMainThreadRequired should be called. If the property is set to true then item.Refresh()
must be called within a QueuedTask.Run()
. If item.IsMainThreadRequired
is set to false, then any thread can be used though BackgroundTask.Run()
is preferred over the UI:
//var contentItem = ...
//Check if the MCT is required for Refresh()
if (contentItem.IsMainThreadRequired) {
//QueuedTask.Run must be used if item.IsMainThreadRequired
//returns true or a CalledOnWrongThreadException will be thrown.
QueuedTask.Run(() => contentItem.Refresh());
}
else {
//if item.IsMainThreadRequired returns false, any
//thread can be used to invoke Refresh(), though
//BackgroundTask is preferred.
contentItem.Refresh();
//Or, via BackgroundTask
ArcGIS.Core.Threading.Tasks.BackgroundTask.Run(() =>
contentItem.Refresh(), ArcGIS.Core.Threading.Tasks.BackgroundProgressor.None);
}
Content can either be accessed via a GetItems<T>
call on the parent item (for example a folder or geodatabase) or on the project instance (or via portal as portal items, ref. portal content). If an item has children that can be enumerated with GetItems then its IsContainer
property will be true. Calling GetItems on the project instance enumerates all of the project items - that is, all of the content that has been added to the project at that point in time - whereas calling GetItems on a folder or geodatabase item, for example, enumerates all of the external items that they each contain (regardless of whether the folder or geodatabase have been added to the project or not). GetItems on a "container" (like a folder or geodatabase) always searches one level deep. To perform a multi-level search (e.g. to drill down through a folder hierarchy), the returned Items should be tested for "IsContainer" equals true and their content likewise enumerated with GetItems (recursively) and so on.
As GetItems<T>
is a generic function, it can be constrained to return only items of a particular type using its template parameter "T". This is especially useful when searching the content of the project for just items of a particular type. For example:
//get just the maps - use MapProjectItem
var maps = Project.Current.Getitems<MapProjectItem>();
//Get a specific map
var map = Project.Current.GetItems<MapProjectItem>().FirstOrDefault(
m => m.Name == "Map 1");
//get just the database connections - use GDBProjectItem
var gdbs = Project.Current.Getitems<GDBProjectItem>();
//get just the layouts - use LayoutProjectItem
var layouts = Project.Current.Getitems<LayoutProjectItem>();
//etc.
//Just get them all - no constraints
var allItems = Project.Current.GetItems<Item>();
As GetItems<T>
returns an IEnumerable
, the result can be extended with Linq expressions to further refine and filter the retrieved content. For example, this is a search on the first folder connection of a given name in the project for any mxd files it contains:
//Declarations in a view model, for example
private static readonly object _lock = new object();
private ObservableCollection<Item> _mxdResults = = new ObservableCollection<Item>();
...
//Call to BindingOperations to sync access to the ObservableCollection, eg in the ctor
BindingOperations.EnableCollectionSynchronization(_mxdResults , _lock);
...
///<summary>Property for binding of search results</summary>
public ObservableCollection<Item> MxdResults => _mxdResults ;
/// <summary>Performs the search for mxds on the given folder</summary>
private async Task SearchFirstFolderForMxdsAsync(string Folder) {
// find the folder project item - Use Ling FirstOrDefault extension on the returned IEnumerable
var folder = Project.Current.GetItems<FolderConnectionProjectItem>().FirstOrDefault(f => f.Path == Folder);
await QueuedTask.Run(() => {
lock(_lock) {
_mxdResults.Clear();
//Call GetItems to get the folder content (one level deep)
foreach (var item in folder.GetItems()) {
if (item.Name.EndsWith("mxd"))
_mxdResults.Add(item);
}
}
}
Content returned from GetItems are snapshot collections. They are not refreshed if the child content of given parent project item changes (e.g. a new file or feature class is added). Content must be re-queried.
Project also provides a public Task<IEnumerable<Item>> SearchAsync(string query)
function that supports a keyword search of project item content based on the information that a given project item may contain in its metadata (e.g. in its keywords, tags, summary, etc.). Refer to topic 9205 in the API Reference.
FindItems is useful when you already have a path or catalog path to an item on disk or in a geodatabase. FindItems first searches for the content in the Pro index (which includes content that has been added to the project). If the item is found in the index, the item is returned. If the item is not found in the index, FindItems checks the path to assure the content is valid, and, if so, creates a new item. Additionally, if the path is either to a folder or a file geodatabase, then the item is added to the project and will be indexed. If the path is bad, null is returned.
//retrieve a pdf
var pdfPath = @"E:\Temp\Layout1.pdf";
var pdf = Project.Current.FindItem(pdfPath);
//retrieve a folder (the folder will be added to the project)
var folderPath = @"E:\Data\SampleData";
var folder = Project.Current.FindItem(folderPath);
//retrieve a feature class and select it in the Catalog pane (assuming the catalog pane has focus)
var fcPath = @"E:\Pro\CommunitySampleData\Interacting with Maps.gdb\Crimes";
var fc = Project.Current.FindItem(fcPath);
If the item(s) is a project content item, it can be further cast to the relevant "ProjectItem" class (i.e. "project items" like map, style, layout, scene, toolbox, etc.)
Assuming you have retrieved an item corresponding to geodatabase content, the next step is usually to access the underlying ArcGIS.Core.Data
dataset it contains. Items corresponding to geodatabase content are usually retrieved from the browse dialog when a user browses into a geodatabase and selects one of the geodatabase objects within it or from an item selected in the Catalog window or pane. There are many types of datasets, some examples are: a feature dataset, a feature class, a table, or a relationship class. The dataset types currently supported are defined by the ArcGIS.Core.Data enumeration DatasetType
A number of methods have been added to the ItemFactory class to facilitate retrieval of dataset and data definition. These are GetDatasetType, GetDataset and GetDefinition. There are also the corresponding CanGetDataset and CanGetDefinition properties.
First, lets examine how to retrieve the geodatabase content from an item chosen in the Browse dialog.
var openDlg = new OpenItemDialog
{
Title = "Select a Feature Class",
InitialLocation = @"C:\Data",
MultiSelect = false,
BrowseFilter = BrowseProjectFilter.GetFilter(ArcGIS.Desktop.Catalog.ItemFilters.geodatabaseItems_all)
};
//show the browse dialog
bool? ok = openDlg.ShowDialog();
if (!ok.HasValue || openDlg.Items.Count() == 0)
return; //nothing selected
await QueuedTask.Run(() =>
{
// get the item
var item = openDlg.Items.First();
// see if the item has a dataset
if (ItemFactory.Instance.CanGetDataset(item))
{
// get it
using (var ds = ItemFactory.Instance.GetDataset(item))
{
// access some properties
var name = ds.GetName();
var path = ds.GetPath();
// if it's a featureclass
if (ds is ArcGIS.Core.Data.FeatureClass fc)
{
// create a layer
var layer = LayerFactory.Instance.CreateLayer(new Uri(path), MapView.Active.Map);
// continue
}
}
}
});
Next, lets retrieve the geodatabase content from a selection in the Catalog pane. In order to know when an item is selected in the Catalog pane, subscribe to the ProjectWindowSelectedItemsChangedEvent.
// subscribe to event
ProjectWindowSelectedItemsChangedEvent.Subscribe(async (ProjectWindowSelectedItemsChangedEventArgs args) =>
{
if (args.IProjectWindow.SelectionCount > 0)
{
// get the first selected item
var selectedItem = args.IProjectWindow.SelectedItems.First();
await QueuedTask.Run(() =>
{
// get the datasetType
var dataType = ItemFactory.Instance.GetDatasetType(selectedItem);
// get the dataset Defintion
if (ItemFactory.Instance.CanGetDefinition(selectedItem))
{
using (var def = ItemFactory.Instance.GetDefinition(selectedItem))
{
if (def is ArcGIS.Core.Data.FeatureClassDefinition fcDef)
{
var oidField = fcDef.GetObjectIDField();
var shapeField = fcDef.GetShapeField();
var shapeType = fcDef.GetShapeType();
}
else if (def is ArcGIS.Core.Data.Parcels.ParcelFabricDefinition pfDef)
{
string ver = pfDef.GetSchemaVersion();
bool enabled = pfDef.GetTopologyEnabled();
}
// etc
}
}
// get the dataset
if (ItemFactory.Instance.CanGetDataset(selectedItem))
{
using (var ds = ItemFactory.Instance.GetDataset(selectedItem))
{
if (ds is ArcGIS.Core.Data.FeatureDataset fds)
{
// open featureclasses within the feature dataset
// var fcPoint = fds.OpenDataset<FeatureClass>("Point");
// var fcPolyline = fds.OpenDataset<FeatureClass>("Polyline");
}
else if (ds is FeatureClass fc)
{
var name = fc.GetName() + "_copy";
// create
LayerFactory.Instance.CreateLayer(new Uri(fc.Path), MapView.Active.Map);
}
else if (ds is Table table)
{
var name = table.GetName() + "_copy";
var stParams = new StandaloneTableCreationParams(table);
stParams.Name = name;
// create
StandaloneTableFactory.Instance.CreateStandaloneTable(stParams, MapView.Active.Map);
}
}
}
});
}
});
Note: If you are using ArcGIS Pro 2.8 or previous, then accessing the underlying dataset from the item requires a different pattern
- Access the path from the Item.Path property.
- Parse out the geodatabase connection path from the item path (this can be a path to a file gdb, sde file, or even folder).
- Instantiate the datasource pointed to by the connection path.
- Retrieve the dataset named in the Item.Name property from the datasource.
If you are starting from a path (and not an item) it is actually more straightforward to create an Item from the path first and then follow the 4 step procedure above rather than parsing the path for both the datasource and dataset name directly (and attempting to skip creating an Item).
This example illustrates retrieving a feature class from an item returned from the browse dialog:
//using ArcGIS.Desktop.Catalog;
//using ArcGIS.Desktop.Core;
//using ArcGIS.Desktop.Framework.Threading.Tasks;
//using ArcGIS.Core.Data;
var openFc = new OpenItemDialog {
Title = "Select a Feature Class",
InitialLocation = @"C:\Data\GDB_data",
MultiSelect = false,
//filter for feature classes
BrowseFilter = BrowseProjectFilter.GetFilter(ArcGIS.Desktop.Catalog.ItemFilters.featureClasses_all)
};
//show the browse dialog
bool? ok = openFc.ShowDialog();
if (!ok.HasValue || openFc.Items.Count() == 0)
return;//nothing selected
//retrieve the selected feature class
QueuedTask.Run(()=> {
var fc_item = openFc.Items.First();
//see below for the GDBItemHelper class
using (var fc = GDBItemHelper.GetDatasetFromItem(fc_item) as FeatureClass)) {
//do something with the fc
using (var rows = fc.Search()) {
//etc
}
}
...
This snippet shows the implementation of a GDBItemHelper class that can be used for extracting the path from a File GDB, Enterprise GDB, or Shapefile GDB item and instantiating its contained dataset:
//using ArcGIS.Core.Data;
//
//GDBItemHelper utility class for retrieving datasets from File, Enterprise, or Shapefile GDB items
internal static class GDBItemHelper {
// Keywords
public const string FeatureClassKeyword = "Feature Class";
public const string FeatureDatasetKeyword = "Feature Dataset";
public const string TableKeyword = "Table";
public const string RelationshipClassKeyword = "Relationship Class";
//Must use QueuedTask
public static Dataset GetDatasetFromItem(Item item) {
//self-documenting...
if (!QueuedTask.OnWorker)
throw new ArcGIS.Core.CalledOnWrongThreadException();
//File
if (item.TypeID.StartsWith("fgdb_") || item.TypeID.EndsWith("_fgdb"))
return OpenDatasetForExtension(".gdb", item);
//Enterprise
if (item.TypeID.StartsWith("egdb_") || item.TypeID.EndsWith("_egdb"))
return OpenDatasetForExtension(".sde", item);
//Shape
if (item.TypeID.StartsWith("shapefile_"))
return OpenDatasetForExtension(".shp", item);
return null;
}
//use this flavor if you only have a path
public static Dataset GetDatasetFromPath(string path) {
//self-documenting...
if (!QueuedTask.OnWorker)
throw new ArcGIS.Core.CalledOnWrongThreadException();
//check the path is valid - File, Enterprise, Shape
int indexOfgdb = path.LastIndexOf(".gdb", StringComparison.InvariantCultureIgnoreCase);
if (indexOfgdb == -1)
indexOfgdb = path.LastIndexOf(".sde", StringComparison.InvariantCultureIgnoreCase);
if (indexOfgdb == -1)
indexOfgdb = path.LastIndexOf(".shp", StringComparison.InvariantCultureIgnoreCase);
if (indexOfgdb == -1)
return null;
//make the item
var item = ItemFactory.Instance.Create(path);
//retrieve the dataset
return GetDatasetFromItem(item);
}
private static Dataset OpenDatasetForExtension(string extension, Item item) {
int indexOfgdb = item.Path.LastIndexOf(extension,
StringComparison.InvariantCultureIgnoreCase);
if (indexOfgdb == -1)
return null;
string gdbPath = item.Path.Substring(0, indexOfgdb + extension.Length);
if (extension == ".sde") {
using (var geodatabase = new Geodatabase(
new DatabaseConnectionFile(new Uri(gdbPath)))) {
if (item.TypeKeywords.Contains(FeatureClassKeyword))
return geodatabase.OpenDataset<FeatureClass>(item.Name);
if (item.TypeKeywords.Contains(FeatureDatasetKeyword))
return geodatabase.OpenDataset<FeatureDataset>(item.Name);
if (item.TypeKeywords.Contains(TableKeyword))
return geodatabase.OpenDataset<Table>(item.Name);
if (item.TypeKeywords.Contains(RelationshipClassKeyword))
return geodatabase.OpenDataset<RelationshipClass>(item.Name);
}
}
else if (extension == ".gdb") {
using (var geodatabase = new Geodatabase(
new FileGeodatabaseConnectionPath(new Uri(gdbPath)))) {
if (item.TypeKeywords.Contains(FeatureClassKeyword))
return geodatabase.OpenDataset<FeatureClass>(item.Name);
if (item.TypeKeywords.Contains(FeatureDatasetKeyword))
return geodatabase.OpenDataset<FeatureDataset>(item.Name);
if (item.TypeKeywords.Contains(TableKeyword))
return geodatabase.OpenDataset<Table>(item.Name);
if (item.TypeKeywords.Contains(RelationshipClassKeyword))
return geodatabase.OpenDataset<RelationshipClass>(item.Name);
}
}
else if (extension == ".shp") {
var shapePath = System.IO.Path.GetDirectoryName(gdbPath);
using (var shape = new FileSystemDatastore(new FileSystemConnectionPath(
new Uri(shapePath),
FileSystemDatastoreType.Shapefile))) {
return shape.OpenDataset<FeatureClass>(item.Name);
}
}
return null;
}
}
The Item class includes these two properties which provide access to the item’s metadata as an XML document in the ArcGIS metadata format.
An item’s metadata lets you document the item’s content. For example, you can describe where the item’s data came from, how recent it is, what processes have been run on it, what information is available in the fields of its attribute table, and how the item should be used including any legal disclaimers regarding that use. Learn more about viewing and editing metadata in ArcGIS Pro: view and edit metadata.
The item’s metadata is returned as a string representing the ArcGIS metadata XML document. Use that string to create an XML document that can be manipulated using the XML parser of your choice. For example, you can transform the provided XML to an HTML page that can be displayed outside of ArcGIS Pro. Or, you can use the XML parser’s methods to programmatically update the metadata content and save the changes back to the original item using the SetXml method. The metadata saved back to the item must be in the ArcGIS metadata format.
The ArcGIS metadata format is documented in the ArcGIS Metadata Toolkit, which can be downloaded from the Esri Support site. The toolkit contains an XML DTD that defines the structure of an ArcGIS metadata XML document. It also contains an Excel spreadsheet that documents the elements, and indicates if they are populated automatically by ArcGIS, which metadata styles they participate in, where they appear in the metadata editor, and so on. Sample XML documents are also provided to help correlate the ArcGIS metadata format with standard XML formats such as the FGDC CSDGM and ISO 19115/19139 standards.
The context (usually "what is selected") of either the Catalog Pane or a Catalog View can be accessed via their ArcGIS.Desktop.Core.IProjectWindow
interface (see topic 14659).
To retrieve the catalog pane or any catalog view use:
-
Project.GetActiveCatalogWindow()
if you want the active catalog view. If no catalog view is active, this returns null. -
Project.GetCatalogPane()
if you want the catalog pane (whether it is active or not). SpecifycreateIfNecessary=false
if you do not the catalog pane created if it has not been created previously. -
FrameworkApplication.ActiveWindow
and test it forIProjectWindow
. If the ActiveWindow is an IProjectWindow it can be either of the catalog pane or a catalog view otherwise the IProjectWindow will be null. -
FrameworkApplication.Panes
enumeration for a specific catalog view (active or not).
//Get the active catalog window - either the pane ~or~ a catalog view
var window = FrameworkApplication.ActiveWindow as ArcGIS.Desktop.Core.IProjectWindow
if(window != null) {
...
//Get the Catalog pane (whether it is the active window or not)
var catalog = Project.GetCatalogPane();//will create the pane if needed
...
//enumerate the panes collection
foreach (var pane in FrameworkApplication.Panes) {
...
Accessing an item selection requires the IProjectWindow (catalog pane or view) whose selection you want access and enumerating its IEnumerable<Item> SelectedItems { get; }
property. Each catalog window maintains its own independent selection (view or the pane). Subscribe to the ProjectWindowSelectedItemsChangedEvent
event to be notified of selection changes.
//Get the active catalog window - either the pane ~or~ a catalog view
var window = FrameworkApplication.ActiveWindow as ArcGIS.Desktop.Core.IProjectWindow
var item = window?.SelectedItems.First();
//do something with the selection...
//Get the Catalog pane (whether it is the active window or not)
var catalog = Project.GetCatalogPane();//will create the pane if needed
//get whatever is selected on it
var items = catalog.SelectedItems;
Selection is performed on project items on the project tab of the catalog pane or catalog views. To perform a selection of items on a catalog window, use its IProjectWindow.SelectItemAsync
method (topic19182.html). In no particular order:
- Retrieve the item to be selected
- Get the IProjectWindow (catalog pane or view) you want to select the item on
- [Optional] Get the container you want the item selected in (some items can live in more than one container)
Retrieve the item using any of the methods available for searching or browsing for items such as GetItems. The IProjectWindow should be acquired as described in the Catalog Context above. The last parameter to SelectItemAsync is the container within which you want the specified item to be selected. Catalog content can, in some cases, be browsed either via its "primary" container or, because it may represented as a physical file or folder, via the Folders container (assuming that its parent folder has been added to the project). The same is true of geodatabase content, such as a feature class, which can be browsed via its parent geodatabase item within the "Databases" container or, possibly, the "Folders" container.
When the SelectItemAsync container
parameter is set to null
, the first occurrence of the item found in any container is the one that is selected. If Multiple containers can hold a particular item, they will be searched in the same order as their visual order/arrangement within the catalog window (pane or view) you are selecting it in. For example, selecting a map or toolbox:
//"projectWindow" can be either the catalog pane or a catalog view...
//Maps only occur in the "Maps" container so no container need be specified
string mapName = "Map";
var map = Project.Current.GetItems<MapProjectItem>().FirstOrDefault(m => m.Name == mapName);
projectWindow.SelectItemAsync(map, true, null);//optionally "await"
//Select the toolbox in the Toolboxes container. Because it is searched
//before "Folders", and null is specified, the toolbox within the Toolboxes container
//will be selected.
string gpName = "Interacting with Maps.tbx";
var toolbox = Project.Current.GetItems<GeoprocessingProjectItem>().FirstOrDefault(tbx => tbx.Name == gpName);
projectWindow.SelectItemAsync(toolbox, true, null);//optionally "await"
Specifying a Container
For those cases where the container within which you want a particular item selected cannot be inferred, the container must be specified. To access the container for use in selecting items, use Project.Current.ProjectItemContainers
to enumerate through the available containers*.
Containers have a localizable display name (their "Name" attribute) which is shown in the catalog windows as well as a non-localizable "type" or "Path" attribute. The "Path" attribute is the preferred attribute to use when identifying a specific container. It correlates with the value for the "key" parameter for Project.Current.GetProjectItemContainer(string key)
as well. The complete set of containers in catalog is listed below along with their display name and path.
Note: Project.Current.ProjectItemContainers
, like many collections in Pro, is a snapshot selection. What that means is, depending on the actual content of a given project at any given point in time, the list of instantiated project containers can vary. In other words, depending on your project content, some containers can be null. (Databases, Folders, Layouts, Locators, Maps, Styles, and Toolboxes are always present). There are also non-visible internal project containers within the collection of containers which can be ignored.
* Project containers are all registered in the esri_core_projectContainers
category in the ADGeoDatabase.daml.
Display Name (English) | Path or "Key" (Non-localizable) | Item content |
Databases | GDB | Database content |
Folders | FolderConnection | Files and Folders |
Layouts | Layout | Layouts |
Locators | LocatorsConnection | Locators |
Maps | Map | Maps |
Raster Function Templates | RasterFunctionTemplates | Raster function templates |
Reviewer Batch Jobs | DataReviewerBatchJobs | Reviewer batch jobs |
Reviewer Results | DataReviewerResources | Reviewer results |
Servers | ServerConnection | Server connections |
Styles | Style | Styles |
Tasks | Task | Tasks |
Toolboxes | GP | Toolboxes |
Workflows | WorkflowConnection | Workflows |
Use the path attribute to select a given container from the collection or the key value with GetProjectItemContainer
- depending on your project content some containers can be null:
//Selecting the maps container
var maps = Project.Current.ProjectItemContainers.First(c => c.Path == "Maps");
//or with key
maps = Project.Current.GetProjectItemContainer("Map");
//Selecting the Folders container
var folders = Project.Current.ProjectItemContainers.First(c => c.Path == "FolderConnection");
folders = Project.Current.GetProjectItemContainer("FolderConnection");
//Selecting the Databases container
var databases = Project.Current.ProjectItemContainers.First(c => c.Path == "GDB");
databases = Project.Current.GetProjectItemContainer("GDB");
Assuming the desired item has been retrieved along with the relevant catalog window and container, perform the selection:
Select the given item in the container using its SelectItemAsync
method.
//retrieve a feature class and select it in the Catalog pane (assuming the catalog pane has focus)
var fcPath = @"E:\Pro\CommunitySampleData\Interacting with Maps.gdb\Crimes";
var fc = Project.Current.FindItem(fcPath);
//Get the Folders container
var folderContainer = Project.Current.GetProjectItemContainer("FolderConnection");
//Select the fc
var projectWindow = Project.GetCatalogPane();
await projectWindow.SelectItemAsync(fc, true, folderContainer);
//Get a toolbox and select it in the Folder container, assuming its parent
//folder has been added to the list of Folders
string gpName = "Interacting with Maps.tbx";
var toolbox = Project.Current.GetItems<GeoprocessingProjectItem>().FirstOrDefault(tbx => tbx.Name == gpName);
var folderContainer = Project.Current.ProjectItemContainers.First(c => c.Path == "FolderConnection");
var projectWindow = Project.GetCatalogPane();
await projectWindow.SelectItemAsync(toolbox, true, folderContainer);
Subscribe to ArcGIS.Desktop.Core.Events.ProjectWindowSelectedItemsChangedEvent
to be notified of selection changes on any catalog window (pane or views). The ProjectWindowSelectedItemsChangedEventArgs
identifies the IProjectWindow
and its DAML Id, that triggered the selection changed event. The IProjectWindow con the event args an be accessed to retrieve what is selected.
//register for selection changed (eg in a dockpane)
internal class LayoutEventSpyViewModel : DockPane {
protected override Task InitializeAsync() {
ArcGIS.Desktop.Core.Events.ProjectWindowSelectedItemsChangedEvent.Subscribe((args) => {
var names = string.Join(",", args.IProjectWindow.SelectedItems.Select(i => i.Name).ToList());
//etc
});
...
Addins needing to detect, or listen for, changes to the project should subscribe to the ArcGIS.Desktop.Core.Events.ProjectItemsChangedEvent event. ProjectItemsChangedEvent
is fired whenever the collection of project items associated with the project is changed. Addins should examine the ProjectItemsChangedEventArgs.Action
property to determine the nature of the change (add, remove, replace, etc.) and execute whatever is their associated logic accordingly. In this example, the addin code is listening for NotifyCollectionChangedAction.Add
associated with new maps and layouts:
...
ArcGIS.Desktop.Core.Events.ProjectItemsChangedEvent.Subscribe(args => {
//Collect the items involved in the event
var items = new List<Item>();
if (args.ProjectItem is Item item)//just one item
items.Add(item);
else if (args.ProjectItemsCollection != null)//more than one
items.AddRange(args.ProjectItemsCollection);
switch (args.Action) {
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
var layouts = items.OfType<LayoutProjectItem>()?.ToList() ??
new List<LayoutProjectItem>();
//TODO process new layout(s)
var maps = items.OfType<MapProjectItem>()?.ToList() ??
new List<MapProjectItem>();
//TODO process new map(s)
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
//TODO handle remove
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
//TODO handle replace
break;
default:
break;
}
});
Favorites is a collection of frequently used connections to folders, databases, toolboxes, servers, custom styles and statistical data collections. The FavoritesManager class allows developers to programmatically customize the favorites collection which are accessible in the UI via the Catalog pane or Catalog view. Any changes made to favorites are saved instantly when the change is made and is independent of project saving.
The following example shows how to add a folder to the favorites collection. First create an item using the ItemFactory class. Use the GetFavorite
method to verify the item is not already in the collection. This function returns a non-null Favorite object if the item can be found in the favorites collection. If the favorite doesn't exist, the CanAddAsFavorite
function should be used before adding the item to ensure that the item type is supported by the favorites collection.
var itemFolder = ItemFactory.Instance.Create(@"d:\data");
// is the folder item already a favorite?
Favorite fav = FavoritesManager.Current.GetFavorite(itemFolder);
if (fav == null)
{
if (FavoritesManager.Current.CanAddAsFavorite(itemFolder))
{
fav = FavoritesManager.Current.AddFavorite(itemFolder);
}
}
Just as within the ArcGIS Pro application, if your organization has an enterprise geodatabase, a GIS server, or a folder containing data used by all projects, you can add these items to your favorites and set them to be added automatically to all new projects you create. This behavior is controlled by the addToAllNewProjects
parameter in the AddFavorite or InsertFavorite methods or by the IsAddedToAllNewProjects
property on the Favorite class.
Here's an example of adding a new favorite with the flag set.
var itemFolder = ItemFactory.Instance.Create(@"d:\data");
// is the folder item already a favorite?
Favorite fav = FavoritesManager.Current.GetFavorite(itemFolder);
if (fav == null)
{
if (FavoritesManager.Current.CanAddAsFavorite(itemFolder))
{
fav = FavoritesManager.Current.AddFavorite(itemFolder, true);
}
}
And here's a code example showing the flag being toggled for an existing folder connection.
var itemFolder = ItemFactory.Instance.Create(@"d:\data");
// is the folder item already a favorite?
Favorite fav = FavoritesManager.Current.GetFavorite(itemFolder);
if (fav != null)
{
// if it's already set to be added to all new projects
if (fav.IsAddedToAllNewProjects)
// clear the flag
FavoritesManager.Current.ClearIsAddedToAllNewProjects(fav.Item);
else
// set the flag
FavoritesManager.Current.SetIsAddedToAllNewProjects(fav.Item);
}
To retrieve the current set of favorites use the GetFavorites
method. This returns a readonly list of Favorite items. You can iterate through the favorites, examining each item one by one. The Item
property on the Favorite class gives access to the underlying item object. Here's some sample code illustrating this.
var favorites = FavoritesManager.Current.GetFavorites();
foreach (var favorite in favorites)
{
bool isAddedToAllProjects = favorite.IsAddedToAllNewProjects;
// retrieve the underlying item of the favorite
Item item = favorite.Item;
// Item properties
var itemType = item.TypeID;
var path = item.Path;
// if it's a folder item
if (item is FolderConnectionProjectItem)
{
}
// if it's a goedatabase item
else if (item is GDBProjectItem)
{
}
// else
}
Finally the FavoritesChangedEvent
is fired every time the favorites collection is changed. Addins interested in changes to the favorites collection should subscribe to this event.
ArcGIS.Desktop.Core.Events.FavoritesChangedEvent.Subscribe((args) =>
{
// favorites have changed
int count = FavoritesManager.Current.GetFavorites().Count;
});
ArcGIS Pro allows developers to programmatically create and configure browse dialog filters for use with the OpenItemDialog
and SaveItemDialog
to control what is visible and can be browsed.
To create browse dialog filters, developers can either create an instance of the BrowseProjectFilter class
configuring it with the item types they wish to filter for, or can use one of the many predefined filters, or can do both. In Pro, filters are identified by DAML ids which are registered in the "esri_browseFilters" category in the respective DAML files for each Pro extension.
To retrieve a Pro filter at runtime, use the BrowseProjectFilter.GetFilter(filterName)
static method where filterName
is the DAML id of the filter to be retrieved. Pro also provides an ArcGIS.Desktop.Catalog.ItemFilters class which has a number of properties defined representing the DAML ids for filters for many of the most common ArcGIS Pro content types. Refer to ProSnippets: Browse Dialog Filters for usage examples of every ArcGIS Pro filter. By default, a new (unconfigured) BrowseProjectFilter will browse all file types supported by Pro.
//Retrieve the pre-defined filter for all file types
var fileFilter = BrowseProjectFilter.GetFilter("esri_browseDialogFilters_browseFiles");
fileFilter.FileExtension = "*.*";//restrict to specific extensions as needed
fileFilter.BrowsingFilesMode = true;
//Specify a name to show in the filter dropdown combo box - otherwise the name
//will show as "Default"
fileFilter.Name = "All Files";
//This is equivalent to configuring a filter to retrieve all supported file types
var defaultFilter = new BrowseProjectFilter();
//Specify a name to show in the filter dropdown combo box - otherwise the name
//will show as "Default"
defaultFilter.Name = "All Pro Files";
//Retrieve the pre-defined filter for adding content to a map using ItemFilters
//Note: this is an example of a composite filter which is covered in the next
//section
var contentFilter = BrowseProjectFilter.GetFilter(ItemFilters.composite_addToMap);
//Use the filter with the OpenItemDialog
var dlg = new OpenItemDialog() {
BrowseFilter = fileFilter, //or use defaultFilter or contentFilter...
Title = "Browse Content"
};
//show the dialog and retrieve the selection if there was one
if (!dlg.ShowDialog().Value)
return;
var item = dlg.Items.First();
Filters can be combined with other filters to build your own composites. Composite filters show up as multiple entries in the Open and Save ItemDialogs filter combos - with each entry representing an individual filter contained within the overall composite. For example, the screenshot below shows the names of the individual filters comprising the esri_browseDialogFilters_composite_addToMap
filter - identified by the ItemFilters.composite_addToMap
member (and used in the example above):
To create a composite filter, add each individual filter to be used in the composite to the BrowseProjectFilter's Filters
collection via its AddFilter
method. In the following example a composite filter is created to browse for both .lyr and .lyrx files:
var compositeFilter = new BrowseProjectFilter();//this will be our composite
//Add the Pro filter for .lyr files
compositeFilter.AddFilter(BrowseProjectFilter.GetFilter(
"esri_browseDialogFilters_layers_lyr"));
//Add the Pro filter for .lyr _X_ files
compositeFilter.AddFilter(BrowseProjectFilter.GetFilter(
"esri_browseDialogFilters_layers_lyrx"));
//Display the composite filter in an Open Item dialog
var dlg = new OpenItemDialog {
Title = "Open LYR and LYRX files",
InitialLocation = @"E:\Pro",
BrowseFilter = compositeFilter
};
bool? ok = dlg.ShowDialog();
Notice that the names of both the filters show up in the browse dialog:
At its most granular level, filters work by filtering in (or out) items based on their underlying type id. Type ids are string identifiers assigned to each, individual, item type in Pro to uniquely identify its given content type. Content types include file types such as mxds, layer files, package types and so forth as well as geodatabase types and online types as well. Content type ids are declared in the Pro extension daml files within the esri_item
category. The complete Pro type id reference can be found here: ArcGIS Pro TypeID Reference. The corresponding type id for a given item is accessed via its Item.TypeID property.
Content types can be added or removed to an existing filter via the BrowseProjectFilter
AddCanBeTypeId and AddMustNotBeTypeId methods. Using our previous example, instead of making a composite filter to show .lyr and .lyrx files, we will instead modify the esri_browseDialogFilters_layers_lyrx
filter to also include .lyr files. The example uses BrowseProjectFilter.AddCanBeTypeId("layer_general")
to add the type id "layer_general" to the filter. layer_general
is the corresponding type id for .lyr files:
var layerFileFilter = BrowseProjectFilter.GetFilter(
"esri_browseDialogFilters_layers_lyrx"));
//Add lyr files to this browse filter by type id
layerFileFilter.AddCanBeTypeId("layer_general");
//Provide a display name for the filter (optional)
layerFileFilter.Name = "Layer Files (LYRX) and Layer Files (LYR)";
//TODO: Show the OpenItemDialog as before...
Notice this is a single filter for both .lyr and .lyrx files and not a composite as before:
Type ids can also be used in-lieu of predefined filters to create your own custom browse experience from scratch. In the following example, the filter is configured to browse only for polygon features. Notice the use of BrowseProjectFilter.AddCanBeTypeId("fgdb_fc_polygon")
to specify just polygon feature classes as the filtered type to be shown in the dialog:
//In this case we do not use a pre-defined filter
var polyFilter = new BrowseProjectFilter();//this will be our polygon-only filter
polyFilter.AddCanBeTypeId("fgdb_fc_polygon");//filter only polygons
polyFilter.Name = "Polygons only";
//Display the filter in an Open Item dialog
var dlg = new OpenItemDialog {
Title = "Open Polygon Feature Classes",
InitialLocation = @"E:\Pro",
BrowseFilter = polyFilter
};
bool? ok = dlg.ShowDialog();
You can further configure the browsing behavior of the filter by enabling or disabling browsing into specific container types (such as file geodatabases or folders) using AddDoBrowseIntoTypeId and AddDontBrowseIntoTypeId respectively.
In conjunction with type ids, filters also allow similar customizations via predefined BrowseProjectFilter.FilterFlags
. The complete set of available filter flags are found here: BrowseProjectFilter.FilterFlag enumeration. They work in exactly the same way as type ids except that the flags operate at a higher-level of granularity (than type ids). An individual flag typically represents the consolidation of multiple type ids where the name of the flag gives an indication of the respective content types it filters. For example the flags BrowseProjectFilter.FilterFlag.FeatureClass
, BrowseProjectFilter.FilterFlag.Layer
, and BrowseProjectFilter.FilterFlag.AddToMap
represent feature class, layer file, and "all types suitable for adding to a map" content types respectively. In many cases they are synonymous with equivalent (predefined) filters declared in ItemFilters
.
Use flags in the same way as you use type ids. Add or Exclude content types via the AddCanBeFlag and AddMustNotBeFlag methods and configure the browse behavior of containers with flags via AddDontBrowseIntoFlag.
Use of flags is not mutually exclusive from the use of type ids. In fact, Flags can be combined with type ids to provide both a coarse and very fine grained level of filter customization. For example a flag can be used to "add" a large number of content types to a filter which can then be refined by excluding or including very specific content types via their type id. For example, here we create a browse filter to show all feature content except polygon feature classes using a combination of the BrowseProjectFilter.FilterFlag.FeatureClass
flag and fgdb_fc_polygon
type id.
var noPolyFilter = new BrowseProjectFilter();//this will be our polygon-only filter
//Show all feature class types using the FeatureClass flag
noPolyFilter.AddMustBeFlag(BrowseProjectFilter.FilterFlag.FeatureClass);
//Refine the filter to exclude polygons
noPolyFilter.AddMustNotBeTypeId("fgdb_fc_polygon");
noPolyFilter.Name = "No Polygons";
//Display the filter in an Open Item dialog
var dlg = new OpenItemDialog {
Title = "No Polygon Feature Classes",
InitialLocation = @"E:\Pro",
BrowseFilter = noPolyFilter
};
bool? ok = dlg.ShowDialog();
Browse places are the set of available nodes shown in the treeview (in the left pane) of the Open and Save item dialogs. There are currently three available "browse places" (all shown by default): A Project, Portal (or "Online"), and Computer browse place, each of which can be expanded to browse its content. Which browse places are included "in" or excluded "from" the dialog can be controlled via the BrowseProjectFilter
Includes and Excludes collections. Add the string identifier of the browse place to be included or excluded from the corresponding collection to the relevant "Includes" or "Excludes" collection (see below). Note: Browse Places are always implicitly included so "including" a browse place is, in reality, equivalent to a no-op.
The project browse place node can be further refined by including or excluding individual item containers from within it by specifying their container path or "key" in the same "Includes" or "Excludes" collections. By default, all project containers are included in the Project browse place.
Open and Save Item Dialog Browse Place Identifiers
Browse Place | Identifier | Notes |
---|---|---|
Project | project_browse_place_project | Can be customized via container keys |
Portal (Online) | esri_browsePlaces_Online | |
Computer | esri_browsePlaces_Computer |
In this example, the Project browse place is limited to showing just the Folders, Databases, Styles, and Servers containers. The Portal browse place has been excluded. The dialog is using a default browse project filter (no explicit filtering specified). The Project and Computer browse places did not have to be explicitly included to be shown:
var defaultFilter = new BrowseProjectFilter();
//Exclude Portal. Project and Computer are implicitly included.
defaultFilter.Excludes.Add("esri_browsePlaces_Online");
//Customize the containers shown in the Project Browse Place.
//Listing _any_ included container restricts the Project Browse Place to
//showing _just those explicitly included_ in the list.
defaultFilter.Includes.Add("FolderConnection");
defaultFilter.Includes.Add("Style");
defaultFilter.Includes.Add("GDB");
defaultFilter.Includes.Add("ServerConnection");
var dlg = new OpenItemDialog {
Title = "Customized Browse Places",
InitialLocation = @"E:\Pro",
BrowseFilter = defaultFilter
};
bool? ok = dlg.ShowDialog();
Note: The complete list of project containers can be found in the Public Containers table in this document.
BrowseProjectFilters can be declared in DAML in addition to being configured in code. A new browse filter in DAML must be registered as a component with the esri_browseFilters
Pro category. The newly added browse filter component specifies:
-
A unique identifier. This will be specified as the "id" attribute. This string will be passed as a parameter to the BrowseProjectFilter constructor to create an instance of the filter.
-
A
<content>
child element containing:-
displayName
attribute. -
include
attribute that corresponds to the BrowseProjectFilter.Includes collection. -
exclude
attribute that corresponds to the BrowseProjectFilter.Excludes collection.
-
-
One or more filter configuration child elements, each of which can have multiple
<type>
child elements with an id attribute. These elements are used to build the "Allow" and "Deny" list of typeIDs and/or flags to display in the filter:-
<canBeTypeIds>
- TypeIDs that will be displayed by the filter. -
<canBeFlags>
- Content type flags to be displayed by the filter. -
<mustNotBeTypeIds>
- Specific TypeIDs to be excluded by the filter. -
<mustBeFlags>
- Content type flags that browsed content must be -
<mustNotBeFlags>
- Content type flags that will be excluded -
<doBrowseIntoTypeIds>
- TypeIDs that you can browse into. For example, using the typeID "raster_tiff" will allow the filter to browse into tiff images. -
<dontBrowseIntoTypeIds>
- Specific TypeIDs to prevent from being browsable. -
<dontBrowseIntoFlags>
- Content type flags of containers not to be browsed into
-
As an example, here is a DAML code snippet that creates a new filter to display just line feature classes within File Geodatabases only:
<ArcGIS>
...
<categories>
<updateCategory refID="esri_browseFilters">
<insertComponent id="NewLineFeatures_Filter">
<content displayName="Line feature class in FGDB" include="FolderConnection, GDB"
exclude="esri_browsePlaces_Online">
<canBeTypeIds>
<type id="fgdb_fc_line"/>
</canBeTypeIds>
<dontBrowseIntoFlags>
<type id="DontBrowseFiles" /><!-- note this is a flag not a type id -->
</dontBrowseIntoFlags>
<doBrowseIntoTypeIds>
<type id="database_fgdb" />
</doBrowseIntoTypeIds>
</content>
</insertComponent>
</categories>
....
With this filter defined in the add-in Config.daml, it is available for use at anytime (by any add-in) in the Pro session. Invoke the BrowseFilterClass constructor passing in the DAML id of the custom filter as its parameter - NewLineFeatures_Filter
in this case.
var customFilterFromDaml = new BrowseProjectFilter("NewLineFeatures_Filter");
var dlg= new OpenItemDialog {
Title = "Open Line Feature classes",
InitialLocation = @"C:\Data",
BrowseFilter = customFilterFromDaml
};
bool? ok = dlg.ShowDialog();
An example of creating a custom filter to display your own custom items can be found in the following ProGuide: ProGuide: Custom items, step 6.
The Sign On Control is a UI component similar to the core sign on UI at the top right of the the ArcGIS Pro application. Use this control within an Add-in or Configuration to allow users to sign into ArcGIS Online or a portal. If the user is already signed-in, user details are displayed.
Add the control to a view
xmlns:coreControls="clr-namespace:ArcGIS.Desktop.Core.Controls;assembly=ArcGIS.Desktop.Core"
<coreControls:SignOnControl x:Name="signOn"/>
The control has a number of read-only dependency properties which can be used to display the following information
- SignedOnDisplayName
- SignedOnInitials
- SignedOnUserName
- SignedOnFullName
- SignedOnOrganizationName
- ActivePortalUri
- IsSignedIn
You can also listen to the SignOnStatusChanged event with the SignOnStatusChangedEventArgs containing the same information.
signOn.SignOnStatusChanged += SignOn_SignOnStatusChanged;
private void SignOn_SignOnStatusChanged(object sender, ArcGIS.Desktop.Core.Controls.SignOnStatusChangedEventArgs args)
{
var isSignedIn = args.IsSignedIn;
var userName = args.SignedOnUserName;
var portal = args.CurrentPortalUri;
var fullName = args.SignedOnFullName;
var orgName = args.SignedOnOrganizationName;
}
A configuration using the SignOn Control can be found at ProStartPageConfig.
The Recent Projects Control is a component similar to the project list UI displayed on the Open or New Project pages of the ArcGIS Pro application. It displays the recently opened and pinned ArcGIS Pro projects. Use this control within a Configuration on a custom StartPage to replicate the standard ArcGIS Pro experience. You can also use the control with an Add-in as required.
Add the control to a view
xmlns:coreControls="clr-namespace:ArcGIS.Desktop.Core.Controls;assembly=ArcGIS.Desktop.Core"
<coreControls:RecentProjectsControl x:Name="recentProjects"
ViewType="List"
ShowHorizontalScroll="Auto"
ShowVerticalScroll="Auto" />
Customize the UI by setting the IsTitleVisible, IsFilterVisible, IsViewTypesVisible, IsSortVisible, IsBrowseProjectsVisible flags. You can also set the ViewType to be "List" or "Tile".
The list of recent and pinned projects can be retrieved by the read-only dependency properties RecentProjects and PinnedProjects.
The SelectedProjectChanged event fires when a project is selected, allowing you to specify a custom action. Typically this would be opening the selected project, but allows other actions to be specified.
A configuration using the RecentProjectsControl can be found at ProStartPageConfig.
The Recent Templates Control is a component similar to the template list UI displayed on the Open or New Project pages of the ArcGIS Pro application. It displays the recently used and pinned ArcGIS Pro project template. Use this control within a Configuration on a custom StartPage to replicate the standard ArcGIS Pro experience. You can also use the control with an Add-in as required.
Add the control to a view
xmlns:coreControls="clr-namespace:ArcGIS.Desktop.Core.Controls;assembly=ArcGIS.Desktop.Core"
<coreControls:RecentTemplatesControl x:Name="recentTemplates" />
Customize the UI by setting the IsTitleVisible or IsBrowseTemplatesVisible flags.
The list of recent and pinned templates can be retrieved by the read-only dependency properties RecentTemplates and PinnedTemplates
The SelectedTemplateChanged event fires when a template is selected, allowing you to specify a custom action. Typically this would be opening a project with the specified template, but allows other actions to be specified.
A configuration using the RecentTemplatesControl can be found at ProStartPageConfig.