Custom button OnUpdate logic does not get executed when using DelegateCommands Model

2567
3
Jump to solution
12-15-2015 12:30 AM
Highlighted
Esri Contributor

I’m trying to test implementation of custom button which uses DelegateCommands Model as described in the following wiki page:

ProGuide Buttons: Use a static module method as a button class definition

I am able to execute the referenced static method on my module, but cannot execute the OnUpdate logic support via the naming convention.

In my Daml:

<modules>

  <insertModule id="MyAddIn_Module" className="MainModule" autoLoad="false" caption="Module1">

    <tabs>

      <tab id="MyTab" caption="My Tab">

        <group refID="MyGroup" />

      </tab>

    </tabs>

    <groups>

      <group id="MyGroup" caption="My Group" appearsOnAddInTab="true">

        <button refID="MyCustomButton" size="large" />

      </group>

    </groups>

    <controls>

      <button id="MyCustomButton" caption="My Custom Button" className="MyAddIn_Module:OnMyCustomButtonClick" loadOnClick="true" condition="esri_mapping_onlyFeatureLayersSelectedCondition" smallImage="Images\GenericButtonBlue16.png" largeImage="Images\GenericButtonBlue32.png">

        <tooltip heading="Tooltip Heading">Tooltip text<disabledText /></tooltip>

      </button>

    </controls>

  </insertModule>

</modules>

In my MainModule.cs:

namespace MyAddIn

{

    internal class MainModule : Module

    {

        private static MainModule _this = null;

        ....

        internal static async Task OnMyCustomButtonClick()

        {

            await QueuedTask.Run(() =>

            {

                System.Diagnostics.Debug.WriteLine("OnClick called");

            });

        }

        internal static async Task CanOnMyCustomButtonClick()

        {

            await QueuedTask.Run(() =>

            {

                System.Diagnostics.Debug.WriteLine("OnUpdate called");

            });

        }

    }

}

In the code above, CanOnMyCustomButtonClick method does not get executed. I’m assuming that OnUpdate logic support via the naming convention is equivalent of overriding OnUpdate() of Button base class. Do I need an additional step to make the CanOnMyCustomButtonClick method to be get executed?

Note: If I explicitly create MyCustomButton and referece it from DAML (className="MyCustomButton"), the OnUpdate method is executed automatically.

internal class MyCustomButton : Button

{

    protected override void OnClick()

    {

        System.Diagnostics.Debug.WriteLine("OnClick called");

    }

    protected override void OnUpdate()

    {

        base.OnUpdate();

        System.Diagnostics.Debug.WriteLine("OnUpdate called");

    }

}

Reply
0 Kudos
1 Solution

Accepted Solutions
Highlighted
Esri Contributor

Hi Shohei,

So let me also provide some guidance.

First: the documentation you reference is not clear on use of DelegateCommands and we need to do a better job of explaining them and we will do that for 1.2.

Second: the DelegateCommand update must be a property, not a method. It must be a property that returns bool. You can actually see that in the Module1.cs class file that Thomas points out in the sample in his reply. This is a subtlety that is not clearly documented.

So, to get your code working please try this implementation:

internal static void OnMyCustomButtonClick() {

            System.Diagnostics.Debug.WriteLine("OnClick called");

        }

        internal static bool CanOnMyCustomButtonClick {

            get {

                System.Diagnostics.Debug.WriteLine("OnUpdate called");

                return true;

            }

        }

Notice that CanOnMyCustomButtonClick is a bool property.

Also, I have not used QueuedTask as this is not really necessary and would be inefficient in the Update property given the frequency with which it is called but I get it that you were probably just experimenting with different API characteristics and what-not in your code.

Last, to a point Thomas raises with regards to conditions and also an Update implementation. Use of the condition in daml is much more efficient than coding update logic (whether via an OnUpdate override or a "Can..." update property.

However, if you do have both, the condition in daml and are updating your enabled state via Update code, then the Update code wins with one exception: The initial enabled state of the button as shown on the ribbon.

Before the button has been clicked, the Framework will use the condition in the daml to show its initial enabled state. Once the button has been clicked then the button state is controlled by its Update logic and the condition is ignored. You can observe this behavior with your implementation:

Return false from your update property and keep your "esri_mapping_onlyFeatureLayersSelectedCondition" condition in the DAML. Before clicking the button, select and unselect a feature layer in the TOC. You should notice the button's enabled state toggling based on the condition true/false. Once you click the button it will always be disabled regardless of the condition. (Note also that your OnClick logic is never called....why?)

This would be akin to coding this for an OnUpdate override:

protected override void OnUpdate() {

            this.Enabled = false;//disable the button the moment it is clicked.

        }

View solution in original post

3 Replies
Highlighted
Esri Contributor

You have a condition on the button declaration that takes precedence and is redundant if you would like to use the Command pattern. The CanOnMyCustomButtonClick in your example will take the role of the condition.

Please take a look at this example

https://github.com/Esri/arcgis-pro-sdk-community-samples/tree/master/Map-Exploration/FeatureSelectio... on the syntax and usage.

Reply
0 Kudos
Highlighted
Esri Contributor

Hi Shohei,

So let me also provide some guidance.

First: the documentation you reference is not clear on use of DelegateCommands and we need to do a better job of explaining them and we will do that for 1.2.

Second: the DelegateCommand update must be a property, not a method. It must be a property that returns bool. You can actually see that in the Module1.cs class file that Thomas points out in the sample in his reply. This is a subtlety that is not clearly documented.

So, to get your code working please try this implementation:

internal static void OnMyCustomButtonClick() {

            System.Diagnostics.Debug.WriteLine("OnClick called");

        }

        internal static bool CanOnMyCustomButtonClick {

            get {

                System.Diagnostics.Debug.WriteLine("OnUpdate called");

                return true;

            }

        }

Notice that CanOnMyCustomButtonClick is a bool property.

Also, I have not used QueuedTask as this is not really necessary and would be inefficient in the Update property given the frequency with which it is called but I get it that you were probably just experimenting with different API characteristics and what-not in your code.

Last, to a point Thomas raises with regards to conditions and also an Update implementation. Use of the condition in daml is much more efficient than coding update logic (whether via an OnUpdate override or a "Can..." update property.

However, if you do have both, the condition in daml and are updating your enabled state via Update code, then the Update code wins with one exception: The initial enabled state of the button as shown on the ribbon.

Before the button has been clicked, the Framework will use the condition in the daml to show its initial enabled state. Once the button has been clicked then the button state is controlled by its Update logic and the condition is ignored. You can observe this behavior with your implementation:

Return false from your update property and keep your "esri_mapping_onlyFeatureLayersSelectedCondition" condition in the DAML. Before clicking the button, select and unselect a feature layer in the TOC. You should notice the button's enabled state toggling based on the condition true/false. Once you click the button it will always be disabled regardless of the condition. (Note also that your OnClick logic is never called....why?)

This would be akin to coding this for an OnUpdate override:

protected override void OnUpdate() {

            this.Enabled = false;//disable the button the moment it is clicked.

        }

View solution in original post

Highlighted
Esri Contributor

Hi Thomas and Charles,

Thank you for your replies. Based on your answers, I understand the followings:

  • To utilize the naming convention of DelegateCommands, Update must be property which returns bool.
  • Condition attribute and DelegateCommands Update are used for the same purpose and if both of them are present, Update will always win except to determine the initial state of the button.

These are very useful information for me. I’ve fixed my code as below and get the Update to be executed. Thank you!

Config.daml

<insertModule id="MyAddIn_Module" className="MainModule" autoLoad="false" caption="Module1">

  <tabs>

    <tab id="MyTab" caption="My Tab">

      <group refID="MyGroup" />

    </tab>

  </tabs>

  <groups>

    <group id="MyGroup" caption="My Group" appearsOnAddInTab="true">

      <button refID="MyCustomButton" size="large" />

    </group>

  </groups>

  <controls>

    <button id="MyCustomButton" caption="My Custom Button" className="MyAddIn_Module:OnMyCustomButtonClick" loadOnClick="true" smallImage="Images\GenericButtonBlue16.png" largeImage="Images\GenericButtonBlue32.png">

      <tooltip heading="Tooltip Heading">Tooltip text<disabledText /></tooltip>

    </button>

  </controls>

</insertModule>

MainModule.cs

internal static void OnMyCustomButtonClick()

{

    System.Diagnostics.Debug.WriteLine("OnClick called");

}

internal static bool CanOnMyCustomButtonClick

{

    get

    {

        System.Diagnostics.Debug.WriteLine("OnUpdate called");

        return true;

    }

}

Reply
0 Kudos