ListContentDockpaneViewModel.cs ================== using System; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Data; using System.Windows.Input; using ArcGIS.Core.Data; using ArcGIS.Desktop.Catalog; using ArcGIS.Desktop.Core; using ArcGIS.Desktop.Framework; using ArcGIS.Desktop.Framework.Contracts; using ArcGIS.Desktop.Framework.Threading.Tasks; namespace ProAppModule1 { internal class ListContentDockpaneViewModel : DockPane { private const string _dockPaneID = "ProAppModule1_ListContentDockpane"; private const string _menuID = "ProAppModule1_ListContentDockpane_Menu"; private ICommand _openGdbCmd; private ObservableCollection<GdbItem> _gdbDefinitions = new ObservableCollection<GdbItem>(); private readonly object _lockGdbDefinitions = new object(); protected ListContentDockpaneViewModel() { // By default, WPF data bound collections must be modified on the thread where the bound WPF control was created. // This limitation becomes a problem when you want to fill the collection from a worker thread to produce a nice experience. // For example, a search result list should be gradually filled as more matches are found, without forcing the user to wait until the // whole search is complete. // To get around this limitation, WPF provides a static BindingOperations class that lets you establish an // association between a lock and a collection (e.g., ObservableCollection<T>). // This association allows bound collections to be updated from threads outside the main GUI thread, // in a coordinated manner without generating the usual exception. BindingOperations.EnableCollectionSynchronization(_gdbDefinitions, _lockGdbDefinitions); } public ICommand OpenGdbCmd { get { return _openGdbCmd ?? (_openGdbCmd = new RelayCommand(() => OpenGdbDialog(), () => true)); } } /// <summary> /// Show the DockPane. /// </summary> internal static void Show() { var pane = FrameworkApplication.DockPaneManager.Find(_dockPaneID); pane?.Activate(); } /// <summary> /// Text shown near the top of the DockPane. /// </summary> private string _heading = "Show GDB Content"; public string Heading { get { return _heading; } set { SetProperty(ref _heading, value, () => Heading); } } private string _gdbPath = string.Empty; public string GdbPath { get { return _gdbPath; } set { SetProperty(ref _gdbPath, value, () => GdbPath); LookupItems(); } } public ObservableCollection<GdbItem> GdbDefinitions { get { return _gdbDefinitions; } set { SetProperty(ref _gdbDefinitions, value, () => GdbDefinitions); } } private void OpenGdbDialog() { OpenItemDialog searchGdbDialog = new OpenItemDialog { Title = "Find GDB", InitialLocation = @"C:Data", MultiSelect = false, Filter = ItemFilters.geodatabases }; var ok = searchGdbDialog.ShowDialog(); if (ok != true) return; var selectedItems = searchGdbDialog.Items; foreach (var selectedItem in selectedItems) GdbPath = selectedItem.Path; } private void LookupItems() { QueuedTask.Run(() => { using (Geodatabase fileGeodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(GdbPath)))) { IReadOnlyList<FeatureClassDefinition> fcdefinitions = fileGeodatabase.GetDefinitions<FeatureClassDefinition>(); lock (_lockGdbDefinitions) { _gdbDefinitions.Clear(); foreach (var definition in fcdefinitions) { _gdbDefinitions.Add(new GdbItem() { Name = definition.GetName(), Type = definition.DatasetType.ToString() }); } } IReadOnlyList<TableDefinition> tbdefinitions = fileGeodatabase.GetDefinitions<TableDefinition>(); lock (_lockGdbDefinitions) { foreach (var definition in tbdefinitions) { _gdbDefinitions.Add(new GdbItem() { Name = definition.GetName(), Type = definition.DatasetType.ToString() }); } } } }).ContinueWith(t => { if (t.Exception == null) return; var aggException = t.Exception.Flatten(); foreach (var exception in aggException.InnerExceptions) System.Diagnostics.Debug.WriteLine(exception.Message); }); } } /// <summary> /// Button implementation to show the DockPane. /// </summary> internal class ListContentDockpane_ShowButton : Button { protected override void OnClick() { ListContentDockpaneViewModel.Show(); } } /// <summary> /// Button implementation for the button on the menu of the burger button. /// </summary> internal class ListContentDockpane_MenuButton : Button { protected override void OnClick() { } } }
================
<UserControl x:Class="ProAppModule1.ListContentDockpaneView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:extensions="clr-namespace:ArcGIS.Desktop.Extensions;assembly=ArcGIS.Desktop.Extensions"
mc:Ignorable="d"
d:DataContext="{Binding Path=ProAppModule1.ListContentDockpaneViewModel}"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<extensions:DesignOnlyResourceDictionary Source="pack://application:,,,/ArcGIS.Desktop.Framework;componentThemesDefault.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" LastChildFill="true" KeyboardNavigation.TabNavigation="Local" Height="30">
<TextBlock Grid.Column="1" Text="{Binding Heading}" VerticalAlignment="Center" HorizontalAlignment="Center" Style="{DynamicResource Esri_TextBlockDockPaneHeader}">
<TextBlock.ToolTip>
<WrapPanel Orientation="Vertical" MaxWidth="300">
<TextBlock Text="{Binding Heading}" TextWrapping="Wrap"/>
</WrapPanel>
</TextBlock.ToolTip>
</TextBlock>
</DockPanel>
<Grid Grid.Row="1" HorizontalAlignment="Stretch" Margin="5" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Margin="0,0,5,0" VerticalAlignment="Center" Text="GDB Path:" Style="{DynamicResource Esri_TextBlockRegular}"/>
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding GdbPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Center"></TextBox>
<Button Grid.Column="2" Grid.Row="0" Command="{Binding OpenGdbCmd}" Style="{DynamicResource Esri_Button}" VerticalAlignment="Center">Open GDB</Button>
</Grid>
<DataGrid Grid.Row="2" Margin="5"
ScrollViewer.CanContentScroll="True"
AutoGenerateColumns="True"
HorizontalAlignment="Stretch"
HeadersVisibility="Column"
RowHeaderWidth="0"
ItemsSource="{Binding Path=GdbDefinitions, Mode=OneWay}"
Style="{DynamicResource Esri_DataGrid}">
</DataGrid>
</Grid>