Skip to content

ProGuide Buttons

Wolf edited this page Nov 6, 2024 · 4 revisions
Language:      C#
Subject:       Framework
Contributor:   ArcGIS Pro SDK Team <[email protected]>
Organization:  Esri, http://www.esri.com
Date:          12/21/2022
ArcGIS Pro:    3.4
Visual Studio: 2022

This ProGuide explains the step by step process on how to declare a button. However this is for reference only. The recommended approach is to run the button item template.

In this topic

How to declare a button
Control the enabled state of a button using a condition
Show custom text on a tooltip when the button is disabled
Set the extended caption for a button
Add a key tip to a button
Preload a button
Delegate Commands
Change a button caption
Change a button condition
Remove a button
Position a button into a group owned by a different module
Access a button at runtime
Execute a button at runtime
Create a checked button


How to declare a button

Buttons are the least complex of all controls and are declared in DAML using the button element within the controls container.

A button is declared using the id, caption, className and tooltip attributes. You can also specify the largeImage and smallImage attributes if your button is to have an image associated with it.

The button is referenced on a group using the button control with the refID attribute.

<groups>
   <group id="MyGroup" caption="Group 1">
      <button refID="ProAppModule_Button1" size="large" />
   </group>
</groups>
<controls>
   <button id="ProAppModule_Button1" caption="Button 1" className="MyCustomButton" 
  largeImage="Images\GenericButtonBlue32.png" smallImage="Images\GenericButtonBlue16.png">
      <tooltip heading="Tooltip Heading">Show a message box with the project URI<disabledText />
      </tooltip>
   </button>
</controls>

The button implementation is specified with the className attribute. The MyCustomButton class specified above inherits from the ArcGIS.Desktop.Framework.Contracts.Button base class. Override the virtual methods OnClick and OnUpdate to perform whatever custom behavior is desired.

internal class MyCustomButton : ArcGIS.Desktop.Framework.Contracts.Button
{
   protected override void OnClick()
   {
      string uri = ArcGIS.Desktop.Core.Project.Current.URI;
      ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show($"Project uri {uri}"); 
   }

   protected override void OnUpdate()
   {
      // TODO - add specific code here to control enabled state
   }
}

Control the enabled state of a button using a condition

In most instances, the enabled state of a button relies upon certain conditions within the application. For example, the Add Data button is only enabled when a map pane is opened. Use the condition attribute to assign a predefined condition. For more information about defining states and conditions within DAML, see that section.

<button id="ProAppModule_Button1" caption="Button 1" className="Button1"
  largeImage="Images\GenericButtonBlue32.png" smallImage="Images\GenericButtonBlue16.png" condition="esri_mapping_mapPane">
   <tooltip heading="Tooltip Heading">Show a message box with the project URI<disabledText />
   </tooltip>
</button>

Show custom text on a tooltip when the button is disabled

In addition to controlling the enabled state of a button, you can also add a custom message on the tooltip to explain why the button is disabled. This is achieved using the disabledText attribute of the button's tooltip.

<controls>
  <!-- add your controls here -->
   <button id="ProAppModule_Button1" caption="Button 1" className="Button1" loadOnClick="true" 
        smallImage="Images\GenericButtonBlue16.png" largeImage="Images\GenericButtonBlue32.png">
          <tooltip heading="Tooltip Heading">Show a message box with the project URI
          <disabledText>Text that is shown when the button is disabled</disabledText></tooltip>
   </button>
</controls>

Disabled tooltip

Set the extended caption for a button

Many captions are ambiguous and duplicated many times, for example, Format. To resolve this, use the extendedCaption attribute on controls to provide more details. You do not need to provide an extended caption if there are no name collisions and the meaning of the control is clear based on the regular caption. The extendedCaption appears alongside the caption—in parentheses—in the Customize and Task dialog boxes.

Add a key tip to a button

The ribbon control allows keyboard access to ribbon tabs, groups and items by means of Key Tips. Use the keyTip attribute to add a key tip to your custom button (and tab). You will need to ensure that the key tip chosen for each of your controls is unique amongst all controls on the tab on which it appears.

<controls>
  <!-- add your controls here -->
   <button id="ProAppModule_Button1" caption="Button 1" className="Button1" loadOnClick="true" 
        smallImage="Images\GenericButtonBlue16.png" largeImage="Images\GenericButtonBlue32.png"
        keyTip="CB">
          <tooltip heading="Tooltip Heading">Show a message box with the project URI
          <disabledText>Text that is shown when the button is disabled</disabledText></tooltip>
   </button>
</controls>

Using the ALT key you can see the key tips associated with various tabs and buttons.

Key tips for the application (using ALT) keytips

Key tips for the Add-Intab (using ALT+Z)
keytips_ViewTab

Preload a button

The loadOnClick attribute determines when the button should be created by the framework. By default, controls appear enabled, but are not actually instantiated until they are clicked. This JIT strategy improves resource utilization and startup time by deferring the instantiation of controls until they are initiated by the end user. The default value of the loadOnClick attribute is true. Change this attribute to false to preload the button.

Delegate Commands

Modules support DelegateCommands which are a pattern for simplifying the creation of buttons in the ribbon. Instead of writing a complete button plug-in class that inherits from the abstract button class, you can instead declare that your button is really just a static method on the module class.

In the sample below we are implementing a DelegateCommand using a static method (on the Module1 class) named OnCustomButtonClick. In the DAML, the button element's className attribute holds the id of the Module plus the name of the static method to call separated by a colon ':'.

<insertModule id="MyAddIn_Module" className="Module1" autoLoad="false" caption="Module1">
   <tabs>...</tabs>
   <groups>...</groups>
   <controls>
      <button id="MyAddIn_Module_Button" className="MyAddIn_Module:OnCustomButtonClick" caption="Button1"             largeImage="Images\GenericButtonBlack32.png" smallImage="Images\GenericButtonBlack16.png">
    <tooltip>Tooltip text</tooltip>
</button>
   </controls>
</insertModule> 

In Module1.cs, our static method OnCustomButtonClick implements the OnClick handler:

internal class Module1 : Module {
   //Delegate command OnClick handler
   internal static void OnCustomButtonClick() {
        System.Diagnostics.Debug.WriteLine("Button clicked");
   }
 

Note that DelegateCommand “response” methods should normally be private or internal.

DelegateCommands can additionally support OnUpdate functionality via a static property that returns bool. The property must have the same name as the DelegateCommand OnClick method with the prefix Can.

In this example, the OnClick method is called OnCustomButtonClick so the property must be called **Can**OnCustomButtonClick.

internal class Module1 : Module {
   private static bool _isEnabled = true;

   //Delegate command OnClick handler
   internal static void OnCustomButtonClick() {
        System.Diagnostics.Debug.WriteLine("Button clicked");
   }

   //Delegate command OnUpdate implementation
   internal static bool CanOnCustomButtonClick {
      get {
          //Module1 code must keep '_isEnabled' current
          return _isEnabled;
      }
   }

Note that this DelegateCommand pattern is only suitable for buttons that appear on the ribbon. Delegate commands are also documented in the ProConcepts Framework.

Change a button caption

Update operations can be achieved using the update prefix. In the example below, the caption of a previously inserted button is updated using the updateButton element. Note also the refID attribute that is used to reference existing objects. Updates should exist within an updateModule element, referencing the appropriate module to which the button belongs.

<updateModule refID="acme_MainModule">
   <controls>
      <updateButton refID="esri_SubSystem_Button1" caption="New Caption"/>
   </controls>
</updateModule>

Change a button condition

Not all attributes can be updated. Altering a button's condition is not possible. Conditions can only be set through an insert DAML declaration.

Remove a button

Delete operations can be achieved using the delete prefix. In the example below, a previously inserted button is removed from the UI using the deleteButton element. Note also the refID attribute that is used to reference existing objects.

<updateModule refID="acme_MainModule">
   <controls>
      <deleteButton refID="esri_SubSystem_Button1"/>
   </controls>
</updateModule>

Position a button into a group owned by a different module

Use the updateGroup and insertButton elements to add a button into a group owned by a different module. As this is an update operation your DAML needs an updateModule element, referencing the appropriate module to which the group belongs. The placeWith and insert attributes allow you to position your item relative to another within the group. The insert attribute can have values of "before" or "after".

<modules>
   <updateModule refID="esri_mapping">
      <groups>
         <updateGroup refID="esri_mapping_selectionGroup">
            <insertButton refID="esri_editing_ShowAttributes" size="middle"
                                placeWith="esri_mapping_clearSelectionButton" insert="before" />
         </updateGroup>      
      </groups>    
   </updateModule>    
</modules>

Access a button at runtime

All controls can be accessed and updated at runtime using the FrameworkApplication.GetPlugInWrapper function and the controls identifier.

protected override void OnClick()
{
   IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("acme_ZoomBtn");
   wrapper.Caption = "New Caption";
   wrapper.Tooltip = "New Tooltip";
}

Execute a button at runtime

protected override void OnClick()
{
   IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("esri_mapping_zoomToSelectionButton");
   var command = wrapper as ICommand; // tool and command(Button) supports this

   if ((command != null) && command.CanExecute(null))
      command.Execute(null);
}

Create a checked button

Define the button in DAML as normal. Override the OnClick event in your button class to alter the IsChecked runtime property to set the checked state.

<button id="AppCustomization_CheckedButton" caption="Lock" className="MyCheckedButton" loadOnClick="false" >
   <tooltip heading="Checked button"></tooltip>
</button>
internal class MyCheckedButton : Button
{
   public MyCheckedButton()
   {
      IsChecked = false;
      Caption = "Lock";
      SmallImage = new System.Windows.Media.Imaging.BitmapImage(new Uri(
 @"pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericUnLockNoColor16.png"));
      LargeImage = new System.Windows.Media.Imaging.BitmapImage(new Uri(
 @"pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericUnLockNoColor32.png"));
   }

   protected override void OnClick()
   {
      IsChecked = !IsChecked;

      if (IsChecked)
      {
         Caption = "Unlock";
         SmallImage = new System.Windows.Media.Imaging.BitmapImage(new Uri(
 "pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericLockNoColor16.png"));
         LargeImage = new System.Windows.Media.Imaging.BitmapImage(new Uri(
 "pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericLockNoColor32.png"));
      }
      else
      {
         Caption = "Lock";
         SmallImage = new System.Windows.Media.Imaging.BitmapImage(new Uri(
@"pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericUnLockNoColor16.png"));
         LargeImage = new System.Windows.Media.Imaging.BitmapImage(new Uri(
@"pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericUnLockNoColor32.png"));
      }
   }      
}