|
POST
|
I have a question about using transparency on the text element. Can you tell me where the text element transparency is exposed through the ArcGIS Pro interface? I am unable to find where the transparency property of the text element is set. It does not appear on any ribbon when I select the element that is set to 100% transparent, nor does a transparency property appear within the Text Symbol properties of the text element on the Element tab when I select a text element. I am asking, because I need to manually change the set up the template layout to make all items visible with black text color, but I wanted to also be able to manually set the transparency of the items that I wanted to be opaque or transparent for a specific layout. I prefer to not set the Visible property of the elements to false, since then they cannot be selected on the layout itself. They can only be accessed through the Contents pane for the layout if the Visible property is set to false. The Transparency property allows me to select the elements on the layout, but I don't see where to set it manually.
... View more
05-15-2023
12:22 PM
|
0
|
0
|
1983
|
|
POST
|
Based on the code you provided I have created the following method that finds the text element by the name that is passed to the method and sets the transparency to the value that is passed: public async static void SetTextTransparency(string ElementName, int TextTransparency)
{
// Ensure TextTransparency is within transparency bounds
if (TextTransparency < 0) TextTransparency = 0;
if (TextTransparency > 100) TextTransparency = 100;
var myLayoutView = LayoutView.Active;
if (myLayoutView == null) return;
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
//Reference and load the layout associated with the layout item
Layout lyt = myLayoutView.Layout;
if (lyt == null) return;
//Reference a text element by name
TextElement txtElm = lyt.FindElement(ElementName) as TextElement;
if (txtElm == null) return;
//Change TextProperties
var cimSym = txtElm.GetDefinition();
cimSym.Visible = true;
var cimTextGraphicBase = (cimSym as CIMGraphicElement).Graphic;
if (cimTextGraphicBase == null) return;
cimTextGraphicBase.Transparency = TextTransparency;
txtElm.SetDefinition(cimSym);
});
} I have also rewritten my method for setting the text value to follow a similar coding pattern to make sure that the process of checking for null values is more thorough.
... View more
05-15-2023
10:39 AM
|
1
|
1
|
1992
|
|
POST
|
I am trying to convert an ArcObjects tool written in VB to an ArcGIS Pro SDK tool written in C#. One of the subroutines of my ArcObjects passes a layout graphics container and a text element name on the layout to make the text color black and another subroutine is passed the same kinds of parameters to change the text color to null (invisible). Here is the ArcObjects method for making the color of the text black: Private Sub setTextElementBlackColor(ByVal pGraphicsContainer As ESRI.ArcGIS.Carto.IGraphicsContainer, ByVal strElementName As String)
Dim pActiveView As ESRI.ArcGIS.Carto.IActiveView
Dim bFound As Boolean
Dim pElement As ESRI.ArcGIS.Carto.IElement
Dim pElementProperties As ESRI.ArcGIS.Carto.IElementProperties2
Dim pTextElement As ESRI.ArcGIS.Carto.ITextElement
Dim pTextSymbol As ESRI.ArcGIS.Display.ITextSymbol
Dim pColor As ESRI.ArcGIS.Display.IColor
pActiveView = pGraphicsContainer
pColor = New ESRI.ArcGIS.Display.RgbColorClass
pColor.NullColor = False
pColor.RGB = RGB(0, 0, 0)
pTextSymbol = New ESRI.ArcGIS.Display.TextSymbolClass
'Element Search escape variable
bFound = False
pGraphicsContainer.Reset()
pElement = pGraphicsContainer.Next()
Do While Not pElement Is Nothing
pElementProperties = pElement
If pElementProperties.Name = strElementName Then
If TypeOf pElement Is ESRI.ArcGIS.Carto.ITextElement Then
pTextElement = pElement
pTextSymbol = pTextElement.Symbol
pTextSymbol.Color = pColor
pTextElement.Symbol = pTextSymbol
pActiveView.PartialRefresh(ESRI.ArcGIS.Carto.esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)
bFound = True
If Not pTextSymbol Is Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(pTextSymbol)
End If
If Not pTextElement Is Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(pTextElement)
End If
End If
End If
If bFound = False Then
pElement = pGraphicsContainer.Next()
Else
pElement = Nothing
End If
If Not pElementProperties Is Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(pElementProperties)
End If
Loop
If Not pColor Is Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(pColor)
End If
If Not pActiveView Is Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(pActiveView)
End If
End Sub What is the equivalent code in the ArcGIS Pro SDK for changing a layout text element to black or invisible? I have a method for changing the text of a TextElement, but the TextProperties of the element do not include any way to change the text color. Presumably the code would be similar to that code for changing the text element color, but I do not see any sample code in the git hub examples that tells me how to access the color properties of the text element. Here is the code I use to change the text value of the TextElement: public async static void SetTextElement(string ElementName, string TextValue)
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
//Reference and load the layout associated with the layout item
Layout lyt = LayoutView.Active.Layout;
if (lyt != null)
{
//Reference a text element by name
TextElement txtElm = lyt.FindElement(ElementName) as TextElement;
//Change TextProperties
TextProperties txt_prop = txtElm.TextProperties;
txt_prop.Text = TextValue;
txtElm.SetTextProperties(txt_prop);
}
});
}
... View more
05-15-2023
08:46 AM
|
0
|
5
|
2018
|
|
POST
|
I have been trying to use code to call ArcObjects for ArcMap 10.8 from within Python based on various code examples on the web and so far all of them aren't working. So, is it possible to use ArcObjects for ArcMap 10.8 within Python, or does that only work for earlier versions of ArcMap? I have tried installing comtypes and using the first example from this website: https://gist.github.com/AlexArcPy/bf0f1702d6b0d3840f43442a2d5ef5c6 However, although I have changed the path to match my version of ArcMap, the code fails on the line 12 with a "WindowsError: [Error -2147024809] The parameter is incorrect" error when it tries to execute: esriFramework = GetModule(r"C:\Program Files (x86)\ArcGIS\Desktop10.8\com\esriFramework.olb") I also tried using the library on NuGet called UnmanagedExports from Robert Giesecke from https://www.udcus.com/blog/2017/06/27/extending-arcpy-increased-capabilities-arcobjects-and-c However that code fails when I try to run the Python Example Call Function saying that the dll I built does not have a function called "CustomPost" and doesn't even try to execute anything from the dll. I had made sure the x86 build type is selected in the Target Platform of my project properties. I read elsewhere that the UnmanagedExports library is not compatible with Visual Studio 2017, which is the minimum version required by the ArcMap 10.8 SDK. So, is it no longer possible to call ArcObjects for ArcMap 10.8 from within Python?
... View more
01-26-2023
06:36 PM
|
0
|
1
|
1208
|
|
BLOG
|
On September 28, 2022, I released a new version of my Add-In that added an option to search for Township Range and Section(s) within Riverside County. This is how the tool looks: If you only want to find a single Section you can use the keyboard to do all the steps. Type the number of the Township you want (Example 2) and press the Tab key Type the number of the Range you want (Example 6) and press the Tab key. Optionally you can toggle the slider button to change the W and E Direction of the Range by pressing the Enter or Space key and press the Tab key The grid will change at each of the above steps and if any Sections do not fall within Riverside County they will be disabled. Type the number of the Section you want (Example 28) and press the tab key - the number you typed will blank out and the appropriate Section toggle button within the central Township and Range of the grid will be selected (if it is valid in Riverside County). The Launch button will now have focus and you can press the Enter key or Space key on your keyboard to activate the Launch button and zoom to the Section. If you only want to use the mouse you can Left Click on the Township and Range combobox dropdowns and the Slider Button for W and E to chose the Township and Range you want. To select one or more Sections in the grid with the mouse there are several options: You can do a single Left Click on one of the Section toggle buttons to select it and deselect all other selected toggle buttons. If you do a single Left Click while holding the Shift Key on the Keyboard you can select additional Section toggle buttons individually without affecting any selected toggle buttons that you didn't click. If you do a single Left Click while holding the Control Key on the Keyboard you can invert the selection of each Section toggle button individually (if it is unselected, it becomes selected or if it is selected, it becomes unselected). This does not affect any selected toggle buttons you didn't click. You can Left Click, Drag and Release the Left mouse button to select a rectangular group of Section toggle buttons and deselect any selected toggle buttons that are outside of the rectangle. When dragging in the mode the rectangle appears like this: You can Left Click, Drag and Release the Left mouse button while holding the Shift Key on the Keyboard to select all of the Section toggle buttons that fall within the rectangle you drew. The Section toggle buttons that were selected that are outside of the rectangle will be unaffected. When dragging in this mode the rectangle appears like this: You can Left Click, Drag and Release the Left mouse button while holding the Control Key on the Keyboard to invert the selection of Section toggle buttons within the rectangle you drew. The Section toggle buttons that were selected that are outside of the rectangle will be unaffected. When dragging in this mode the rectangle appears like this:
... View more
09-28-2022
11:54 AM
|
4
|
0
|
719
|
|
BLOG
|
December 22, 2025 - The ArcGIS Pro Search Tool has been updated to work in ArcGIS Pro 3.2 including bug fix to support Basic license users and Township, Range and Section(s) mouse selection behavior. I am releasing the 1.1.3 version of an ArcGIS Pro Search Tool for Riverside County that in this release includes nine (9) of the Search options available in the ArcMap version posted in my Blog here. The Searches include Search by: Street Intersection APN (Assessors Parcel Number) PLUS Case (Planning and Land Use System) Assessors Subdivision Name/Number or Assessors Recorders Type Book/Page Survey Map Subdivision Name/Number or Survey Map Recorders Type Book/Page. Township, Range and Section(s) (Released - 9/28/2022) Road Book Page (with the ability to build Road Book Page Layouts when layers are present) (Released - 12/25/2025) Before installing the Add-In, if you have installed any previous version of the Add-In you need to uninstall the prior version first. Open ArcGIS Pro and open the Project Settings page by doing one of the following:. Before opening an ArcGIS Pro project click the Setting button in the lower left-hand corner of the screen: After opening and ArcGIS Pro project click the Project tab in the upper left-hand corner of the screen: Click the Add-In Manager menu item on the left hand side of the Project Setting page Click on the RivCoSearchForms Add-In in the list of My Add-Ins You can verify the version is out of date by reviewing the Date and Version information prior to removing the Add-In Click on the Delete this Add-In button at the bottom right-hand corner of the screen The Add-In will still appear in the list of My Add-Ins until you close ArcGIS Pro, but it will say it is Deleted: After removing the Add-In you must close ArcGIS Pro before you install the new Add-In.. To Install the Add-In download the attached RivCoSearchForms.zip file. Extract and double-click the RivCoSearchForms.esriAddIInX file. Press the Install Add-In button on the Esri ArcGIS Add-In Installation Utility dialog. The press the OK button on the Installation succeeded notification Esri ArcGIS Add-In Installation Utility dialog. Open ArcGIS Pro and open or start a project or you can use the "Start without a template" option. An Add-In tab will have been added to your project, which you can use to choose the Search Option you want and press the cat face Search button to open the search dialog. Open or create a Map or 2D Layout in your project prior to using the cat face search tool. The search tool will verify that your current active map has the layers the tool requires. If necessary it will add them to the map provided that the tool is able to create a Database Connection to the SQL Server Database Platform using the RCIT-19GISP01 Instance with Operating System authentication using the GDB_PUB Database. If you cannot directly connect to Riverside County's GIS data server, but have obtained copies of the appropriate Riverside County Feature Classes in your own geodatabase, you can create the necessary layers by adding the following feature classes to your map and renaming the layer it creates with the layer name shown below: Feature Class Name - Layer Name CENTERLINE_INTERSECTIONS - Search Intersections ADDRESS_POINTS - Search Address Points PARCELS_CONDOS_CREST_VW (or PARCELS_CREST) - Search Parcels PLUS_ACTIVITIES_MODIFIED (or PLUS_ACTIVITIES) - Search PLUS Cases RECORDED_MAPS - Search Survey Maps ROADBOOK_PAGE_INDEX - Search Road Book Page SECTIONS - Search Sections ADDING THE SEARCH TOOL ADD-IN BUTTON AND COMBOBOX TO THE QUICK ACCESS TOOLBAR For easy access to the tool you can add the Search button and combobox for search options to the Quick Access toolbar as a onetime set up. Do the following: Dropdown the Customize Quick Access Toolbar menu as shown and press the Customize the Ribbon option. In the Options dialog scroll to the bottom of the list on the left side of the dialog and press the Quick Access Toolbar option. In the Customize the Ribbon combobox in the Options dialog choose All Commands Type search into the textbox dropdown and choose the Open Search Choice button and press the Add button and then choose the Search (Extended Caption) combobox and press the Add button. The icon for the Open Search Choice button has changed from a Cat to R2D2. The list of tools should look like the items shown below and press the OK button The Quick Access Toolbar should now look like this. You can also access the Search Tools through the Add-in tab: Choose the search you want in the dropdown and press the R2D2 button to launch the search dialog. If you have any questions, please post them here. This Blog will be updated as I release expanded or updated versions of the Search Tools and the date time of each revision publication will be added to the list at the bottom of this blog post. Originally published version 1.0 by Richard Fairhurst on September 20, 2022 at 4:07 PM PST. Updated the Add-In zip file to make improvements to the validations performed in response to user data entry in the APN Search dialog. Published by Richard Fairhurst on September 21, 2022 at 9:30 AM PST. Updated the Add-In zip file to version 1.1 to add a new Township, Range and Section(s) Search dialog option. Published by Richard Fairhurst on September 28, 2022 at 10:38 AM PST. Updated the Add-In zip file to version 1.1.1 to change label placement properties of the Standard Label Engine to label each feature part when the Search layers are added to the map. Published by Richard Fairhurst on October 2, 2022 at 4:45 PM PST. Replaced ArcGIS Pro Search Tool so that it now is for ArcGIS Pro version 3.2 and higher. Changed Open Search Choices button icon from a Cat to R2D2. Published by Richard Fairhurst on August 14, 2025 at 9:00 AM PST. Bug Fix to prevent crashes for Basic license users and for mouse selection behaviors of the Township, Range and Section(s) search option. Published by Richard Fairhurst December 22, 2025 at 4:40 PM PST. Enhancement of Search Road Book tool to build Road Book Pages when a Layout has the appropriate layers. Published by Richard Fairhurst December 25, 2025 at 11:30 AM PST.
... View more
09-20-2022
04:12 PM
|
5
|
2
|
2035
|
|
IDEA
|
@ChrisFoxI had never tried the SQL syntax you outlined, but this expression does work in ArcMap and ArcGIS Pro for related data in the same geodatabase. This syntax is only briefly discussed in the Subqueries section of the SQL reference for query expressions used in ArcGIS website. That section doesn't include an example that was quite as clear or useful to me as the one you have given. I frankly would like to see your example added to that section, since if it had been there years ago I would have been much more likely to see the usefulness of this approach and not had to develop some of the workarounds I came up with. Your example works for file geodatabases as well, despite the warning that file geodatabases only offer limited support for subqueries. The Subqueries section basically says that help for using them is specific to the DBMS documentation of my enterprise geodatabase. Since I've mostly worked with file geodatabases that limitation warning had kept me from even trying to figure out or use Subqueries, but based on the example you have outlined I believe I actually now have a use for them. Thanks.
... View more
09-15-2022
02:40 PM
|
0
|
0
|
2030
|
|
POST
|
I also figured out how to implement a property that can set the IsSelected property of the ListBoxItems of a ListBox so that it supports a TwoWay update when the Selection Mode is set to Extended and it does not have to be passed as a CommandParameter to an ICommand button. I found that the Extended SelectionMode only mostly worked properly when I included the ListBox parameter for VirtualizingStackPanel.IsVirtualizing="False" along with setting the SelectionMode="Extended". It does not appear to trigger a notification when the user actually extends their multiselection in the ListBox, so as far as I can tell the evaluation or programmatic use of the ListBox IsSelected property has to be triggered by Methods and Actions you design in your code. In this example code I am presenting a list of Lot numbers so I made my ItemSource binding to an ObservableCollection called Lots. This ObservableCollection contains ListBoxItems based on a custom class called LotSelector. I had to set up an ItemTemplate for the ListBox so the list would display the Item property of the LotSelector custom class in the ListBox and an ItemContainerStyle of ListBoxItems that would assign the IsSelected property of each ListBoxItem to the IsSelected property of my LotSelector custom class. Here is the xaml for the ListBox: <ListBox x:Name="lbxLots" VirtualizingStackPanel.IsVirtualizing="False" SelectionMode="Extended" ItemsSource="{Binding Lots, Mode=TwoWay}" SelectedItem="{Binding SelectedLot}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Item}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox> I then added a Class Item to my project named LotSelector and defined two classes in the file. The first class is named LotSelector and stores the values and IsSelected state of each ListBoxItem. The second class is named LotItemComparer based on the IComparer class so that the LotSelector instances could be sorted and kept unique using a SortedSet<LotSelector> ViewModel property. Here is the LotSelector.cs file code: using System;
using System.Collections.Generic;
using ArcGIS.Desktop.Framework.Contracts;
namespace RivCoSearchForms
{
public class LotSelector : PropertyChangedBase
{
private string _item;
public String Item
{
get { return _item; }
set
{
_item = value;
NotifyPropertyChanged(() => Item);
}
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
NotifyPropertyChanged(() => IsSelected);
}
}
}
public class LotItemComparer : IComparer<LotSelector>
{
public int Compare(LotSelector x, LotSelector y)
{
// TODO: Handle x or y being null, or them not having Items
return x.Item.CompareTo(y.Item);
}
}
} For the ViewModel I added standard code for my Lots ObservableCollection<LotSelector> property for the ListBox ItemSource and a SelectedLot string property for the SelectedItem property of the ListBox. I also added a SortedSet<LotSelector> private property of the ViewModel to ensure the Lots were distinct and sorted and could be manipulated on the MTC thread. I have included a Command implementation to show how the ListBox could be populated based on the Lot data in a Layer. (I tried to simplify the code of the Command from a more complex version and have not tested it, so the Command code may not run correctly and need correction.) Here is the ViewModel code: private ObservableCollection<LotSelector> _lots = new ObservableCollection<LotSelector>();
public ObservableCollection<LotSelector> Lots
{
get { return _lots; }
set
{
SetProperty(ref _lots, value, () => Lots);
}
}
private string _selectedLot;
public string SelectedLot
{
get { return _selectedLot; }
set
{
SetProperty(ref _selectedLot, value, () => SelectedLot);
// Blank out Book, Page list and text block
Message = null;
}
}
private SortedSet<LotSelector> ListLotsSelected;
public ICommand CmdCancel => new RelayCommand((proWindow) =>
{
// TODO: set dialog result and close the window
(proWindow as ProWindow).DialogResult = false;
(proWindow as ProWindow).Close();
}, () => true);
public ICommand CmdListLotsInLayer => new RelayCommand(async (proWindow) =>
{
ListLotsSelected = new SortedSet<LotSelector>(new LotItemComparer());
// Get the Active Mapview
var ActMap = MapView.Active;
// Get the search layer from its name
var fLayer = ActMap.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name.Equals("Search Lot Layer"));
// If layer exists proceed
if (fLayer != null)
{
// Set up a Queued Task for map changes
int iCount = await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// Execute a Search on the layer
using (RowCursor RecMapCursor = fLayer.Search())
{
int cnt = 0;
// Iterate the found cursor rows
while (RecMapCursor.MoveNext())
{
// Get current row as a feature
using (Feature feature = (Feature)RecMapCursor.Current)
{
// Get the APN value of the feature
LotSelector Lot = new LotSelector();
int number;
bool success = int.TryParse(feature[LotField].ToString(), out number);
if (success)
{
Lot.Item = feature[LotField].ToString().PadLeft(4);
}
else
{
Lot.Item = feature[LotField].ToString();
}
// Set the IsSelected property to select the ListBoxItem
Lot.IsSelected = true;
// Update the ListLotsSelected parameter
ListLotsSelected.Add(Lot);
cnt += 1;
}
}
return cnt;
}
});
if (iCount > 0)
{
Lots.Clear();
foreach (LotSelector _Lot in ListLotsSelected)
{
Lots.Add(_Lot);
}
}
}
}, () => true);
... View more
09-14-2022
06:37 PM
|
0
|
0
|
8761
|
|
POST
|
I figured out the answer. Here is the code I came up with: var ActMap = MapView.Active;
MapView mapView = ActMap;
Camera camera = mapView.Camera;
double scaleFt = camera.Scale/12; // Convert inches to feet
ScaleBar alternatingScaleBar = lyt.FindElement("Alternating Scale Bar") as ScaleBar;
if (alternatingScaleBar != null)
{
CIMDoubleFillScaleBar scaleBarDef = alternatingScaleBar.GetDefinition() as CIMDoubleFillScaleBar;
if (scaleFt <= 4000)
{
scaleBarDef.UnitLabel = "Ft";
string unitJsonFt = "{\"uwkid\":9002}";
var unitFt = ArcGIS.Core.Geometry.Unit.CreateFromJson(unitJsonFt);
scaleBarDef.Units = unitFt;
}
else
{
scaleBarDef.UnitLabel = "Mi";
string unitJsonMi = "{\"uwkid\":9093}";
var unitMi = ArcGIS.Core.Geometry.Unit.CreateFromJson(unitJsonMi);
scaleBarDef.Units = unitMi;
}
alternatingScaleBar.SetDefinition(scaleBarDef);
}
... View more
09-09-2022
10:02 AM
|
2
|
2
|
1391
|
|
POST
|
I have an alternating scalebar in my layout. In my Addin the user selects features they want to locate on the map and zooms to their selection. As long as the map scale required to display all of the features is not zoomed out beyond 1:4000 feet I want the scalebar units to be displayed in Feet and adjust the map scale to make sense for feet. If the map has to zoom out beyond 1:4000 feet to display all of the features I adjust the scale to the nearest 1/2 mile interval that contains all of the features and want the scalebar units to be displayed in Miles. I want to programmatically change the UnitLabel and Units of the scalebar to either feet or miles depending on the scale of the map. I have figured out hoe to access Scalebar's UnitLabel and Units properties. The UnitLabel is set as a string, but the Units needs to be set as an ArcGIS.Core.Geometry.Unit. When I get the Units from the Scalebar as a ArcGIS.Core.Geometry.Unit variable all of its properties that I want to change are read only. How do I set up an instance of an ArcGIS.Core.Geometry.Unit for feet and for Miles so I can set the Scalebar Units property to match the unit rules I am applying to the map scale my Addin is setting? Here is code I have so far: ScaleBar alternatingScaleBar = lyt.FindElement("Alternating Scale Bar") as ScaleBar;
if (alternatingScaleBar != null)
{
CIMDoubleFillScaleBar dfScaleBar = alternatingScaleBar.GetDefinition() as CIMDoubleFillScaleBar;
dfScaleBar.UnitLabel = "Feet";
// I can get the current unit setting of
// the scalebar with this code, but I can't
// change the unit setting of this variable
// and I don't know how to set up my own
// ArcGIS.Core.Geometry.Unit variable that
// I can use to change the Units property.
var sbUnits = dfScaleBar.Units;
}
... View more
09-08-2022
06:44 PM
|
0
|
3
|
1479
|
|
POST
|
I got my original code to work by changing the ICommand declaration to this: public ICommand CmdRemoveFromList
{
get
{
return new RelayCommand((SelectedAPNs) =>
{
// Remove items only when SelectedItem isn't null
if (SelectedAPN != null)
{
// Iterate selected items in APN List
foreach (var item in SelectedAPNs as IList<object>)
{
// Get item as a string
string _APN = item.ToString();
// Remove the APN from the ListParcels variable
ListParcels.Remove(_APN);
}
//Clear the dialog APN list
APNsList.Clear();
// Iterate the APNs in the ListParcels variable
foreach (string ListParcel in ListParcels)
{
// Add the APNs to the dialog list
APNsList.Add(ListParcel);
}
}
}, () => true);
}
} I used the CommandParameter in the RelayCommand declaration, added the as IList<object> to type cast the CommandParameter as an iterable IList of objects in the foreach loop and added }, () => true); at the end of the RelayCommand to provide a return value for the RelayCommand. I verified it worked regardless of whether or not the SelectedItems were visible within the current scroll position of the Listbox. So this is the final solution for the xaml, which is nearly identical to the standard MVVM declarations of a Listbox and Button used in Pro, except that I have added a CommandParameter before the button Command. <ListBox x:Name="lbxAPNList" HorizontalAlignment="Left" Height="143" Margin="10,93,0,0" VerticalAlignment="Top" Width="136" SelectionMode="Extended" ItemsSource="{Binding APNsList}" SelectedItem="{Binding SelectedAPN}"/>
<Button x:Name="btnRemoveFromList" Content="Remove from List" CommandParameter="{Binding ElementName=lbxAPNList, Path=SelectedItems}" Command="{Binding Path=CmdRemoveFromList}"/> And this is the final code for the ViewModel, which uses the standard MVVM code for the Listbox source and SelecedItem and only makes slight variations in the standard MVVM ICommand declaration for the button. private ObservableCollection<string> _apnsList = new ObservableCollection<string>();
public ObservableCollection<string> APNsList
{
get { return _apnsList; }
set
{
SetProperty(ref _apnsList, value, () => APNsList);
}
}
private string _selectedAPN;
public string SelectedAPN
{
get { return _selectedAPN; }
set
{
SetProperty(ref _selectedAPN, value, () => SelectedAPN);
}
}
// ListParcels is populated by another button and matches the listbox
// It ensures the list is alphabetically sorted and all values are unique
public static SortedSet<string> ListParcels { get; set; }
public ICommand CmdRemoveFromList
{
get
{
return new RelayCommand((SelectedAPNs) =>
{
// Remove items only when SelectedItem isn't null
if (SelectedAPN != null)
{
// Iterate selected items in APN List
foreach (var item in SelectedAPNs as IList<object>)
{
// Get item as a string
string _APN = item.ToString();
// Remove the APN from the ListParcels variable
ListParcels.Remove(_APN);
}
//Clear the dialog APN list
APNsList.Clear();
// Iterate the APNs in the ListParcels variable
foreach (string ListParcel in ListParcels)
{
// Add the APNs to the dialog list
APNsList.Add(ListParcel);
}
}
}, () => true);
}
}
... View more
09-07-2022
05:22 PM
|
0
|
0
|
8814
|
|
POST
|
I have a ListBox in my ProWindow which is configured for Extended selection so that the user can select multiple items. I also have a button which is supposed to remove the selected items from the list. I set up the binding for the ListBox as an ObservableCollection. If the Selection mode for the Listbox was Single I would set up a binding for the SelectedItem property of the Listbox. However, when the selection mode is set up for Extended selection I want to use the SelectedItems property, not the SelectedItem property. But I am not sure how to set up the binding in my ViewModel so I can get the IList from the SelectedItems property, which is a read only property. (I don't need to set the SelectedItems, I only need to get it) I have read that there is a way to pass the SelectedItems property of the ListBox to a Command using a CommandParameters property. It says that the CommandParameter should be declared before the Command binding. The button xaml code is supposed to look something like this: <ListBox x:Name="lbxAPNList" HorizontalAlignment="Left" Height="143" Margin="10,93,0,0" VerticalAlignment="Top" Width="136" SelectionMode="Extended" ItemsSource="{Binding APNsList}" SelectedItem="{Binding SelectedAPN}"/>
<Button x:Name="btnRemoveFromList" Content="Remove from List" CommandParameter="{Binding ElementName=lbxAPNList, Path=SelectedItems}" Command="{Binding Path=CmdRemoveFromList}"/> However, I am not sure how to set the ViewModel ICommand declaration up so that I can use that command parameter. I tried the following but it doesn't work, since the code is never triggered: private ObservableCollection<string> _apnsList = new ObservableCollection<string>();
public ObservableCollection<string> APNsList
{
get { return _apnsList; }
set
{
SetProperty(ref _apnsList, value, () => APNsList);
}
}
private string _selectedAPN;
public string SelectedAPN
{
get { return _selectedAPN; }
set
{
SetProperty(ref _selectedAPN, value, () => SelectedAPN);
}
}
// ListParcels is populated by another button and matches the listbox
public static SortedSet<string> ListParcels { get; set; }
public ICommand CmdRemoveFromList(IList<object> SelectedItems)
{
get
{
return new RelayCommand(() =>
{
Message = "";
// Iterate selected items in APN List
foreach (var item in SelectedItems)
{
// Get item as a string
string _APN = item.ToString();
// Remove the APN from the ListParcels SortedList
ListParcels.Remove(_APN);
}
//Clear the dialog APN list
APNsList.Clear();
// Iterate the APNs in the module ListParcels variable
foreach (string ListParcel in ListParcels)
{
// Add the APNs to the dialog list
APNsList.Add(ListParcel);
}
});
}
} Is there a way to get the SelectedItems property of a ListBox for use by a button ICommand declaration that works with the Pro SDK?
... View more
09-07-2022
02:25 PM
|
0
|
4
|
8842
|
|
POST
|
Also, the BindingContext is set up properly in my xaml file since my bindings and code are working property and giving change notifications from my textboxes, buttons and listboxes in response to the get and set code of the properties I set up for them. Only the radiobuttons and checkboxes bindings and notifications are not working. However, you are right that I copy/pasted properties that were set to private and didn't notice it. Changing it to public solved the issue.
... View more
09-06-2022
05:04 PM
|
0
|
0
|
1560
|
|
POST
|
I am having trouble understanding how to implement RadioButons and CheckBoxes using MVVM. It seems that Binding the IsChecked property to a bool get/set ViewModel property doesn't work. What is the trick? Here is my xaml set up for the radio buttons: <StackPanel x:Name="StpMatchType" HorizontalAlignment="Left" Height="65" Margin="19,114,0,0" VerticalAlignment="Top" Width="134">
<RadioButton x:Name="rbStart" GroupName="Test" Content="Start of Name" Height="20" IsChecked="{Binding Path=RBStart,Mode=TwoWay}"/>
<RadioButton x:Name="rbAnyPart" GroupName="Test" Content="Any Part of Name" Height="20" IsChecked="{Binding Path=RBAny,Mode=TwoWay}"/>
<RadioButton x:Name="rbExact" GroupName="Test" Content="Exact Name" Height="20" IsChecked="{Binding Path=RBExact,Mode=TwoWay}"/>
</StackPanel>
<CheckBox x:Name="CbxTitle" Content="Set Map Title" HorizontalAlignment="Left" Margin="19,203,0,0" VerticalAlignment="Top" Height="15" Width="90" IsChecked="{Binding SetTitle}"/>
And here are the ViewModel property set up, but this code is never triggered at set up or when I click on one of the radiobuttons: private bool _rbStart = true;
private bool RBStart
{
get { return _rbStart; }
set
{
_rbStart = value;
NotifyPropertyChanged(() => RBStart);
}
}
private bool _rbAny = false;
private bool RBAny
{
get { return _rbAny; }
set
{
_rbAny = value;
NotifyPropertyChanged(() => RBAny);
}
}
private bool _rbExact = false;
private bool RBExact
{
get { return _rbExact; }
set
{
_rbExact = value;
NotifyPropertyChanged(() => RBExact);
}
}
public bool SetTitle
{
get { return Module1.SetTitle; }
set
{
Module1.SetTitle = value;
NotifyPropertyChanged(() => SetTitle);
}
}
//Module1 Code
private static bool _setTitle;
public static bool SetTitle
{
get { return _setTitle; }
set
{
_setTitle = value;
}
}
It seems like all of the Google examples are overly complex and solving value conversion problems that don't apply to me. Even my code seems like overkill, since the behavior of the set of radiobuttons and checkboxes works fine while it ignores my code. I don't want to modify the default behavior of the radiobuttons or checkboxes at all and I don't really have to be notified or do anything when the user actually changes the radiobutton selection or checkbox state. I just need to be able to access the bool state of these buttons in my ViewModel when I trigger some of my other methods. If I can do that without actually needing to bind any of the radiobuttons or checkboxes, that would be great.
... View more
09-06-2022
04:32 PM
|
0
|
3
|
1606
|
|
POST
|
I have adapted my code to generally follow the the example you provided and was able to get the buttons to close the ProWindow the way I wanted. However, I am not sure I have adapted the code in a way that is fully consistent with keeping the Model separate from the ViewModel. In the example provided the Show button class generated with the ProWindow class seems to have been used as the Model class for the MVVM interactions with the map and/or data. However, I am not using the Show button class created for the ProWindow to launch it. Instead I am using a class that sets up the map with layers that support multiple ProWindow options and launch the appropriate ProWindows based on the choice the user makes in a combobox. That class already has extensive code and I don't want to expand it with the code that the example used in the Show button class. But I am willing to create a new class or call the Show button class to handle the Model portion of the MVVM approach for each ProWindow, if that is recommended. The Cancel button that just closes the ProWindow is fine and fully consistent with the purpose of the ViewModel since it does not interact with the map or any data. The other button, called the Locate button, currently is working the way I want it to work, but it is performing map and data operations in the ViewModel that may be better handled in a separate Model class according to MVVM. I would appreciate comments on which portions of this code should be moved from the ViewModel into a separate Model class to make it more consistent with the approach recommended for MVVM. Here is the code: public ICommand CmdLocate => new RelayCommand(async (proWindow) =>
{
String layerName = "Search PLUS Cases";
var ActMap = MapView.Active;
var fLayer = ActMap.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name.Equals(layerName));
if (fLayer != null)
{
if (PLUSCase != null && PLUSCase != "")
{
string whereClause = "CASE_ID = '" + PLUSCase.Replace("'", "''") + "'";
var iCount = await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// Set up Definition Query filter for the layer
Module1.SetLayerDefinition(fLayer, whereClause, "PLUS Cases");
// Count the filtered features in the layer
var cnt = 0;
using (var cursor = fLayer.Search())
{
while (cursor.MoveNext())
cnt++;
};
if (cnt > 0)
{
// Pause Drawing
ActMap.DrawingPaused = true;
// Clear all selected features in the map
ActMap.Map.SetSelection(null);
// Select the filtered features
fLayer.Select();
// Zoom to Selection
ActMap.ZoomToSelected();
// Reset the camera zoom to zoom out slightly
MapView mapView = ActMap;
// Get the camera for the Active MapView
Camera camera = mapView.Camera;
// Increase the scale by 40%.
camera.Scale *= 1.4;
// Zoom to the camera scale
mapView.ZoomToAsync(camera, TimeSpan.Zero);
//Make the layer visible
fLayer.SetVisibility(true);
// Resure Drawing
ActMap.DrawingPaused = false;
}
else
{
//Make the layer invisible
fLayer.SetVisibility(false);
}
return cnt;
});
// If no selected features
if (iCount == 0)
{
// Show message that No Case Match was found
Message = "No Match Found!";
}
else
// If there are selected features
{
// TODO: set dialog result and close the window
(proWindow as ProWindow).DialogResult = true;
(proWindow as ProWindow).Close();
}
}
}
}, () => true);
... View more
09-06-2022
08:49 AM
|
0
|
0
|
1380
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 03-31-2025 03:25 PM | |
| 1 | 03-28-2025 06:54 PM | |
| 1 | 03-16-2025 09:49 PM | |
| 1 | 03-03-2025 10:43 PM | |
| 1 | 02-27-2025 10:50 PM |
| Online Status |
Offline
|
| Date Last Visited |
Thursday
|