postable command usage

postable command usage

Ning_Zhou
Advocate Advocate
4,710 Views
44 Replies
Message 1 of 45

postable command usage

Ning_Zhou
Advocate
Advocate

seems postable command usage is quite limited, for instance

1) can only send warning message instead of disable command?

2) OOTB duplicate view will name that duplicated view w/ suffix Copy 1, is it possible to name it differently?

0 Likes
Accepted solutions (1)
4,711 Views
44 Replies
Replies (44)
Message 2 of 45

jeremytammik
Autodesk
Autodesk

Regarding your question 2, you could react to the new view creation and rename it afterwards in an additional step, either using DMU or the document changed event.

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 3 of 45

Ning_Zhou
Advocate
Advocate

right, i'll give it a try, thanks Jeremy!

by the way, don't know if i can use ElementTypeDuplicated Event? i assume view duplicating is instance based operation, isn't it?

0 Likes
Message 4 of 45

Sean_Page
Collaborator
Collaborator

If you add Command Binding to the applicable Postable Commands you can indeed disable them by just making them do nothing, or giving the user a warning.

 

DMU is my preferred method to catch new views and rename them.

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 5 of 45

Ning_Zhou
Advocate
Advocate

i did a quick test using document changed event, seems i cannot start transaction in order to change view name, did i miss something?

 

public void AppDocumentChanged(object sender, Autodesk.Revit.DB.Events.DocumentChangedEventArgs args)
{

ICollection<ElementId> views = new FilteredElementCollector(doc).OfClass(typeof(View)).ToElementIds();

ICollection<ElementId> ids = args.GetAddedElementIds();
foreach (ElementId id in ids)
if (views.Contains(id))
{
Element e = doc.GetElement(id);
string name = Regex.Replace(e.Name, @" Copy 1", "_zn"); // name changed successfully
using (Transaction tx = new Transaction(doc))
{
tx.Start("renameTransaction");
try
{
e.Name = name;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
tx.Commit();
}
}
}

0 Likes
Message 6 of 45

Sean_Page
Collaborator
Collaborator

I do not believe you can produce a Transaction during this event. It is a read only event according to the docs.

 

https://www.revitapidocs.com/2015/988dd6cf-fcaa-85d2-622d-c50f13917a13.htm

 

That is why DMU is so nice, it happens in a transaction already so no need to start another one.

 

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 7 of 45

Sean_Page
Collaborator
Collaborator

Also, are you missing { } on your foreach?

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 8 of 45

Ning_Zhou
Advocate
Advocate

thanks spage, can you elaborate on Command Binding thing to disable / give warning? yes, i'll try DMU later as suggested by Jeremy too

0 Likes
Message 9 of 45

Ning_Zhou
Advocate
Advocate

good to know that document changed event is read only, perhaps factory should provide us w/ document changing event too?

i skipped {} as only one if statement here, well, not good practice, thanks again

0 Likes
Message 10 of 45

Sean_Page
Collaborator
Collaborator

See here.

https://boostyourbim.wordpress.com/2013/01/14/how-to-override-commands-in-the-revit-ui-if-you-really...

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 11 of 45

Ning_Zhou
Advocate
Advocate

thanks spage, works great! what if i want to give warning only and continue that command in OOTB way?

0 Likes
Message 12 of 45

Sean_Page
Collaborator
Collaborator

You would need to Remove the command binding after the warning and the use a PostCommand to call the initial CommandId.

 

You can also use Idle handlers to create the binding again if you want it to happen every time and not just the first time.

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 13 of 45

Ning_Zhou
Advocate
Advocate

right, i need to use idle stuff to make sure it works every time, thanks.

0 Likes
Message 14 of 45

Ning_Zhou
Advocate
Advocate

hi spage, for idle event, which scope should i put into, app or cmd? if i put @ app scope i.e. startup then it's one time only, if i put @ cmd scope then how can i use OOTB import command instead of addin command?

0 Likes
Message 15 of 45

Sean_Page
Collaborator
Collaborator

So I have it in the Application level.

 

1. On Startup Biding and capturing the application for later use.

        public Result OnStartup(UIControlledApplication application)
        {
            ControlID.application = application;
            AddCommandBindings(application, "ID_INPLACE_COMPONENT");
            return Result.Succeeded;
        }

 

2. Add the Command Binding and the Method to call when it captures the command.

        private Result AddCommandBindings(UIControlledApplication application, string name)
        {
            RevitCommandId rCommandId = RevitCommandId.LookupCommandId(name);
            if (rCommandId.CanHaveBinding)
            {
                try
                {
                    if (name == "ID_INPLACE_COMPONENT")
                    {
                        application.CreateAddInCommandBinding(rCommandId).Executed += new EventHandler<ExecutedEventArgs>(this.DisableCommand);
                    }
                }
                catch
                {
                    MessageBox.Show("Command " + name + " is already bound.");
                }
            }
            return Result.Succeeded;
        }

 

3. This is the Method the CommandBinding calls when fired

private void DisableCommand(object sender, ExecutedEventArgs args)
        {
            ControlID.postCommand = args.CommandId.Name;
            using (Forms.RevitPostCommandForm rpc = new Forms.RevitPostCommandForm())
            {
                if (rpc.ShowDialog() == DialogResult.OK)
                {
                    UIDocument uiDoc = new UIDocument(args.ActiveDocument);
                    uiDoc.Application.RemoveAddInCommandBinding(args.CommandId);
                    uiDoc.Application.PostCommand(args.CommandId);
                    ControlID.application.Idling += new EventHandler<IdlingEventArgs>(InPlaceComponent_Idling);
                }
            }
        }

 

4. Use the associated idling event to Add the command binding back after it has fired the second time.

        private void InPlaceComponent_Idling(object sender, IdlingEventArgs args)
        {
            AddCommandBindings(ControlID.application, "ID_INPLACE_COMPONENT");
            ControlID.application.Idling -= InPlaceComponent_Idling;
        }

 

 public static class ControlID
        {
            public static UIControlledApplication application { get; set; }
         }

 

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 16 of 45

Ning_Zhou
Advocate
Advocate

thanks spage, works great! except that i have to click OK twice, means that DisableCommand being executed twice, i assume it cannot be avoided because that same command being posted again, perhaps if i missed something?

0 Likes
Message 17 of 45

Sean_Page
Collaborator
Collaborator

I am not somewhere I can test, but I think the Postcommand is queued until after all the other code runs, which means the Idling event is actually firing first. Maybe a Thread.Sleep(2000) in the Idling will give the PostCommand a chance to fire. Not positive on that.

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 18 of 45

Ning_Zhou
Advocate
Advocate

i did quick test, no, doesn't work, just delayed.

0 Likes
Message 19 of 45

Sean_Page
Collaborator
Collaborator

Looking back at my code which is working for me, the only thing I see is that I have the idler handler BEFORE the post command. 

 

private void DisableCommand(object sender, ExecutedEventArgs args)
        {
            ControlID.postCommand = args.CommandId.Name;
            using (Forms.RevitPostCommandForm rpc = new Forms.RevitPostCommandForm())
            {
                if (rpc.ShowDialog() == DialogResult.OK)
                {
                    UIDocument uiDoc = new UIDocument(args.ActiveDocument);
                    uiDoc.Application.RemoveAddInCommandBinding(args.CommandId);
                    ControlID.application.Idling += new EventHandler<IdlingEventArgs>(InPlaceComponent_Idling);
                    uiDoc.Application.PostCommand(args.CommandId);
                }
            }
        }

  

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Message 20 of 45

Ning_Zhou
Advocate
Advocate

thanks spage, still doesn't work, the only difference is that i used window message box

DialogResult result = MessageBox.Show("click OK to continue importing but your action will be logged", "BIM & DD", MessageBoxButtons.OKCancel);
if (result == DialogResult.OK)
{
uiApp.RemoveAddInCommandBinding(arg.CommandId);
uiApp.Idling += new EventHandler<IdlingEventArgs>(OnIdling);
uiApp.PostCommand(arg.CommandId);
}

0 Likes