Check if command is running and set button state with IExternalCommandAvailability

Check if command is running and set button state with IExternalCommandAvailability

gerhard.pawlat
Contributor Contributor
527 Views
4 Replies
Message 1 of 5

Check if command is running and set button state with IExternalCommandAvailability

gerhard.pawlat
Contributor
Contributor

Hello Revit API friends,

I have a general question about handling deactivating and reactivating a ribbon button.
I want to deactivate the ribbon button while the command is running, so it can´t be run multiple times.
But I´m not quite sure what´s the best way to make sure the button is reactivated in any case that can happen.

Please see the following simple example of a command that is starting a wpf form.
- I use the IExternalCommandAvailability right at the start of my command.
- I use a closing eventhandler that triggers the IExternalCommandAvailability if the form is closed.
- I use IExternalCommandAvailability in a catch block.

Is this a 100% save method to amke sure my button is set active again also if error occure in my command? Are there other options for this? Can I check somehow if a command is running or if a wpf form is open?

Unfortunately I can not use a finally block because it will run instantly as the command seems to run async.

Appreciate any help on this topic!
Best regards!

 

 

 

	[Transaction(TransactionMode.Manual)]
	internal class Command : IExternalCommand
	{
		public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
		{
			try
			{
				CommandAvailability.IsCommandRunning = true;
				
				var mainWindow = new MainWindow(commandData.Application);
				mainWindow.Show();

				mainWindow.Closed += (s, e) => CommandAvailability.IsCommandRunning = false;
				return Result.Succeeded;
			}
			catch
			{
				CommandAvailability.IsCommandRunning = false;
				return Result.Succeeded;
			}

		}
	}

 

 

 

 

 

 

 

	public class CommandAvailability : IExternalCommandAvailability
	{
		private static bool isCommandRunning = false;

		public static bool IsCommandRunning
		{
			get { return isCommandRunning; }
			set { isCommandRunning = value; }
		}

		public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories)
		{
			return !isCommandRunning;
		}
	}

 

 

 

0 Likes
Accepted solutions (1)
528 Views
4 Replies
Replies (4)
Message 2 of 5

ricaun
Advisor
Advisor

Hmmm, I don't get it why you are using ExternalCommandAvailability?


I have some code that does some similar, only allow to open one wpf, and if already open. I'm using a static inside the Command, makes more sense in my mind.

 

[Transaction(TransactionMode.Manual)]
public class Command : IExternalCommand
{
    private static SimpleView window;
    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet)
    {
        UIApplication uiapp = commandData.Application;

        if (window is null)
        {
            window = new SimpleView();
            window.Closed += (s, e) => { window = null; };
            window.Show();
        }
        window?.Activate();

        return Result.Succeeded;
    }
}

 

In my sample if you press the command again the window gonna be activated if already opened.

 

 

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

Message 3 of 5

gerhard.pawlat
Contributor
Contributor

Hello @ricaun and thanks for your reply!

Until now I used the same aproach that you are using.

But my requirements now are to have the button greyed out and non clickable while the command is running. This is why i went for using IExternalCommandAvailability. I apologize that I didn´t explain this correct before.

I was hoping that the interface will give me informations on the state of a command, but it´s not. I have to tell the interface if the command should be available or not.

My question is now if it is possible to deactivate (grey out) the button while the command is running, without risking that the button will stay deactivated if my command fails. I´m not shure if I can trust the catch block and eventhandler I´m using now.

0 Likes
Message 4 of 5

ricaun
Advisor
Advisor
Accepted solution

I get it you want to disable the command with your window is open.

 

One thing you could do to make your command better is to join the IExternalCommand and IExternalCommandAvailability in the same class. So you don't need to juggle the static propriety between classes.

 

ricaun_0-1717769532749.gif

Here is a sample.

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using RevitAddin.Forum.Views;
using System;

namespace RevitAddin.Forum.Revit.Commands
{
    [Transaction(TransactionMode.Manual)]
    public class CommandGrey : IExternalCommand, IExternalCommandAvailability
    {
        private static SimpleView window;
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet)
        {
            UIApplication uiapp = commandData.Application;

            try
            {
                window = new SimpleView();
                window.Closed += (s, e) => { window = null; };
                window.Show();
            }
            catch (Exception)
            {
                window = null;
            }

            return Result.Succeeded;
        }

        public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories)
        {
            return window is null;
        }
    }
}

 

Just need to register the command and availability with the same full class name.

 

I believe the try/catch gonna work fine, only gonna grey forever stat open or the event Closed not trigger.

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

Message 5 of 5

gerhard.pawlat
Contributor
Contributor

Thanks for your help @ricaun 🙂