1

I am in need of help.

I have created a dockable WPF within Revit. It is working well and I can 'show' & ;hide' from push buttons.

My aim is to create buttons within the WPF that run custom commands.I dont need to interact or show any information within the WPF, its purely just acting as a push button but in the WPF instead of a ribbon. The commands currently work and can be executed via the Add-In Manager.

Below is the command I am trying to run:

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using System.Collections.Generic;
using System.Linq;

namespace Adams.Commands
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]
    public class PrecastDisallowJoin : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            var uiApplication = commandData.Application;
            var application = uiApplication.Application;
            var uiDocument = uiApplication.ActiveUIDocument;
            var document = uiDocument.Document;

            // Prompt the user to select some walls
            var references = uiDocument.Selection
                .PickObjects(
                ObjectType.Element,
                new WallSelectionFilter(),
                "Please select walls");

            var components = references.Select(r => document.GetElement(r)).ToList();

            // Start a transaction
            using (Transaction t = new Transaction(document, "Change Wall Join Behavior"))
            {
                t.Start();

                // Loop through the selected walls and change their join behavior
                foreach (Reference reference in references)
                {
                    Wall wall = document.GetElement(reference) as Wall;
                    WallUtils.DisallowWallJoinAtEnd(wall, 0);
                    WallUtils.DisallowWallJoinAtEnd(wall, 1);

                }

                // Commit the transaction
                t.Commit();
            }

            return Result.Succeeded;
        }

        public class WallSelectionFilter : ISelectionFilter
        {
            public bool AllowElement(Element elem)
            {
                //return elem is FamilyInstance;
                return elem.Name.Contains("Precast");
            }

            public bool AllowReference(Reference reference, XYZ position)
            {
                return true;
            }
        }
    }
}

My XAML.cs looks like this:

using Autodesk.Revit.UI;
using System.Windows.Controls;
using Adams.Commands;
using System.Windows;


namespace Adams.ui
{
    public partial class Customers : UserControl
    {
        
        public UIDocument uIDocument { get; }
        public ExternalCommandData commandData { get; }

        public Customers(UIDocument uIDocument )
        {
        
            InitializeComponent();
        }
        private void btnStartExcelElementsApp_Click(object sender, RoutedEventArgs e)
        {
            string message = string.Empty;
            PrecastDisallowJoin precastDisallow = new PrecastDisallowJoin();
            precastDisallow.Execute(commandData, ref message, null);
        }
    }

}

Any ideas of what i should be trying? I'm new to creating add-ins and appreciate any help offered. If I have missed any critical info please let me know.

Thank you all

When I tried the above it crashes Revit. Im not sure how to pass the required information in the Execute method in the XAML.

raj
  • 11
  • 1

2 Answers2

0

The Revit dockable dialogue and hence your WPF form lives in a modeless context. It does not execute within a valid Revit API context. A valid Revit API context is only provided by Revit itself, within the event handlers called by Revit when specific events are raised. For instance, clicking a button to launch an add-in external command raises the IExternalCommand.Execute event.

The Building Coder shares a long list of articles on Idling and External Events for Modeless Access and Driving Revit from Outside explaining how to gain access to a valid Revit API context from a modeless state.

You can address your task by using an external event:

The question has also been discussed many times in the Revit API discussion forum, so you can check there for threads including WPF, dockable and external event.

Jeremy Tammik
  • 7,333
  • 2
  • 12
  • 17
0

You can use IExternalEventHandler:

public class MyExternalEvent : IExternalEventHandler
{
    public void Execute(UIApplication app)
    {
        //do your revit related stuff here
    }

    public string GetName()
    {
        return "xxx";
    }   
}

Create external event:

ExternalEvent myExEvent= ExternalEvent.Create(new MyExternalEvent());

In order to effectively use the above you will have to hold reference to "myExEvent" in some ViewModelClass then you will be able to raise this event inside your xaml.cs:

ViewModelClass.TheEvent = myExEvent;
ViewModelClass.TheEvent.Raise();

EDIT: What you were trying to do is unfortunately not acceptable with revit API. WPF window displayed as dockpanel does not have access to valid revit api context. IExternalEventHandler gives you the possibility to somehow link dockpanel user interface with revit api.