Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.

Revit API Forum

Reply
Highlighted
Post 1 of 8
Accepted Solution

Listing all views in a project on a Winform throwing an exception

143 Views, 7 Replies
01-05-2017 01:46 PM

 

I am attempting to create a WinForm which lists all the views in the project as a viewTree. The WinForm run command is then packaged into a Dynamo ZeroTouch node, however the views are not displayed when the form launches, and when I relaunch the form I get an error that line 53 (the foreach statement that attempts to use the view name to populate the viewTree) is "not set to an instance of an object". This is my first attempt to raise and consume events and I've done everything I can to get it to work; what is the cause of this error?

 

The form successfully launches via the dynamo node: 

Capture.JPG

 

 

The exception:

Capture2.JPG

 

 

The code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Autodesk.DesignScript.Runtime;
using Autodesk.DesignScript.Interfaces;
using Autodesk.DesignScript.Geometry;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using RevitServices.Persistence;
using RevitServices.Transactions;
using Revit.Elements;
using Revit.GeometryConversion;

namespace SelectSheetsAndViews
{
    /// <summary> The form class</summary>
    public partial class FormRevitSelect : System.Windows.Forms.Form
    {
        public FormRevitSelect()
        {
            InitializeComponent();
        }

        private void DynamoTreeListSelect_Activated(object sender, System.EventArgs e)
        {

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            List<Autodesk.Revit.DB.View> d1 = new ThresholdReachedEventArgs().Views;
            //List<string> d = new List<string> { "A", "B", "C", "D"};
            foreach (Autodesk.Revit.DB.View x in d1)
            //foreach (string x in d)
            {
                treeView1.Nodes.Add(x.ToString());
            }
        }

        private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {

        }
    }


    /// <summary>A Revit class to get all the sheets and views in the document</summary>
    public class RevitWinForm
    {
        private List<object> _sheetsAndViews;
        private List<object> sheetsAndViewsToDelete;


        internal List<object> GetSheetAndViewsToDelete { get { return sheetsAndViewsToDelete; } }

        private RevitWinForm(List<object> sheetsAndViews)
        {
            _sheetsAndViews = sheetsAndViews;

        }

        internal List<object> GetSheetAndViewList { get { return _sheetsAndViews; } }

        /// <summary>
        /// Function to collect all the views and sheets in the document
        /// </summary> 
        internal static List<Autodesk.Revit.DB.View> SheetsAndView()
        {
            Document doc = DocumentManager.Instance.CurrentDBDocument;
            FilteredElementCollector collector = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Views);
            List<Autodesk.Revit.DB.View> viewList = collector.ToElements() as List<Autodesk.Revit.DB.View>;

            return viewList;
        }


        /// <summary>
        /// The MultiReturn attribute can be used to specify
        /// the names of multiple output ports on a node that 
        /// returns a dictionary. The node must return a dictionary
        /// to be recognized as a multi-out node.
        /// </summary>
        /// <param name="refresh">Refresh</param>
        /// <returns>DynamoTreeListSelect</returns>
        public static string CompactDocument(bool refresh)
        {
            System.Windows.Forms.Application.Run(new FormRevitSelect());
            return "Process Complete";
        }

    }
        
    class Program
    {
        static void Main(string[] args)
        {
            RevitSheetsAndViews v = new RevitSheetsAndViews();
            v.GetRevitViews += v_ViewsOUT;
        }

        static void v_ViewsOUT(object sender, ThresholdReachedEventArgs e)
        {
            List<Autodesk.Revit.DB.View> d1 = e.Views;
        }
    }

    class RevitSheetsAndViews
    {

        private List<Autodesk.Revit.DB.View> views;

        /*public RevitSheetsAndViews(List<Autodesk.Revit.DB.View> viewsOUT)
        {
            views = viewsOUT;
        }
        */
        public RevitSheetsAndViews()
        {
            Document doc = DocumentManager.Instance.CurrentDBDocument;

            FilteredElementCollector collector = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Views);
            views = collector.ToElements() as List<Autodesk.Revit.DB.View>;
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Views = views;
            RevitViewsEventHandler(args);
        }

        protected virtual void RevitViewsEventHandler(ThresholdReachedEventArgs e) //raise the EventHandler delegate and associate GetRevitViews to it
        {
            EventHandler<ThresholdReachedEventArgs> handler = GetRevitViews;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        public event EventHandler<ThresholdReachedEventArgs> GetRevitViews; // declare an event named GetRevitViews. The event is associated with the EventHandler delegate and raised in a method named OnThresholdReached.
    }

    public class ThresholdReachedEventArgs : EventArgs
    {
        public List<Autodesk.Revit.DB.View> Views { get; set; }
    }
}

Hi,

 

the cause is:

When you create a new ThresholdReachedEventArgs instance, its Views property is null, initially.

It must be set before accessing it via a foreach loop.

 

Revitalizer

 

 

Post 2 of 8

Re: Listing all views in a project on a Winform throwing an exception

01-06-2017 12:01 AM in reply to: thomas

Dear Thomas,

 

The answer to every question in the universe is identical:

 

KISS!

 

Unfortunately, that often raises a follow-up question:

 

How?

 

How can I simplify my problem?

 

In programming, simplification can often be achieved by separating separate tasks.

 

That was one of the main goals of object oriented programming OOP when it was invented or at least started emerging six (!) decades ago.

 

In this case, you are talking with the Revit API to obtain information about views, e.g., their names, or whatever other information you wish to display.

 

That is one task.

 

Another issue, completely separate, is to display that information.

 

I suggest you separate the two completely.

 

In other words, talk with the Revit API, obtain the information you require, store it, and stop communicating with Revit.

 

Then, and only then, proceed with other things, such as displaying your stuff.

 

I hope this helps.

 

Good luck!

 

Cheers,

 

Jeremy

 



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

Post 3 of 8

Re: Listing all views in a project on a Winform throwing an exception

01-06-2017 03:17 AM in reply to: thomas

Hi,

 

the cause is:

When you create a new ThresholdReachedEventArgs instance, its Views property is null, initially.

It must be set before accessing it via a foreach loop.

 

Revitalizer

 

 


Don't forget to say 'thank you', it's just one click on the Kudos button.
Post 4 of 8

Re: Listing all views in a project on a Winform throwing an exception

01-06-2017 03:27 AM in reply to: Revitalizer

Hi Rudi,

 

Thank you very much for taking a closer look than I did  :-)

 

And your succinctness :-)

 

Cheers,

 

Jeremy



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

Post 5 of 8

Re: Listing all views in a project on a Winform throwing an exception

01-06-2017 03:34 AM in reply to: jeremytammik

Hi Jeremy,

 

Happy New Year to you - in response to your latest blog posting.

I like the forum, too :-)

 

 

Rudi


Don't forget to say 'thank you', it's just one click on the Kudos button.
Post 6 of 8

Re: Listing all views in a project on a Winform throwing an exception

01-08-2017 04:36 AM in reply to: Revitalizer

Thanks Rudi and Jeremy 

 

Very helpful advice. I realised one of the exceptions was caused by problems with the way I'd written the element collector. Once I fixed that, I acted upon Jeremys advice and did away with extending the Event Handler class, and simply implemented the collector and the rest of my function within the Load event of the form. All now works as expected:

 

Bimorph WinForm.JPG

Post 7 of 8

Re: Listing all views in a project on a Winform throwing an exception

01-09-2017 04:28 AM in reply to: thomas

Dear Thomas,

 

Thank you for your confirmation and congratulations on getting it working!

 

I promoted this thread to a blog post for better legibility and future reference:

 

http://thebuildingcoder.typepad.com/blog/2017/01/distances-switches-kiss-ing-and-a-dino.html#4

 

Cheers,

 

Jeremy

 



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

Post 8 of 8

Re: Listing all views in a project on a Winform throwing an exception

01-09-2017 05:48 AM in reply to: jeremytammik

Cheer Jeremy

 

That's great! If you/those who visit your article are interested, here's the working 'after' code, demonstrating the simplification:

 

namespace Revit
{
    /// <summary> The form class</summary>
    internal partial class FormRevitSelect : System.Windows.Forms.Form
    {
        public List<int> _viewId;

        public List<int> GetViewIds
        {
            get { return _viewId; }
            set { _viewId = value; }
        }

        public FormRevitSelect()
        {
            InitializeComponent();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Document doc = DocumentManager.Instance.CurrentDBDocument;

            BrowserOrganization browserOrg = BrowserOrganization.GetCurrentBrowserOrganizationForViews(doc); //Get the browser item from the document

            FilteredElementCollector collector = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Views);

            List<Autodesk.Revit.DB.Element> viewList = (List<Autodesk.Revit.DB.Element>)collector.ToElements().ToList();
            foreach (Autodesk.Revit.DB.View v in viewList)
            {
                if (v.Name != null & v.ViewType.ToString() != "") //v.ViewType.ToString() != "" is used to remove views which are present in templates by default but only picked up by the element collector. They need to be removed from the list
                {
                    List<FolderItemInfo> folderInfo = browserOrg.GetFolderItems(v.Id).ToList(); //Get the folder information for the view
                    treeView1.Nodes.Add(v.Id.ToString(), v.Name);
                }
            }
        }
    }
}

 

ZeroTouch code for Dynamo library import:

    /// <summary>A Revit class to get all the sheets and views in the document</summary>
    public class DocumentUtilities
    {
        private List<object> _sheetsAndViews;

        internal List<object> GetSheetAndViewsToDelete { get { return _sheetsAndViews; } }

        private DocumentUtilities(List<object> sheetsAndViews)
        {
            _sheetsAndViews = sheetsAndViews;

        }

        /// <summary>
        /// Work in progress
        /// </summary>
        /// <param name="refresh">Refresh to reopen the form</param>
        /// <returns>Revit View Elements</returns>
        public static List<Revit.Elements.Element> ExporttDocument(bool refresh)
        {
            Document doc = DocumentManager.Instance.CurrentDBDocument;

            FormRevitSelect form1 = new FormRevitSelect();
            System.Windows.Forms.Application.Run(form1);

            List<Revit.Elements.Element> vList = new List<Revit.Elements.Element>();
            foreach (int i in form1.GetViewIds)
            {
                Autodesk.Revit.DB.Element v = doc.GetElement( new Autodesk.Revit.DB.ElementId(i) ) as Autodesk.Revit.DB.Element;
                vList.Add( v.ToDSType(true) );
            }
            return vList;
        }
    }

 

Run in Dynamo:

Bimorph Select.PNG

 

 

Result:

Result.PNG

 

Cheers!

 

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post

Revit Exchange Apps

Created by the community for the community, Autodesk Exchange Apps for Revit helps you achieve greater speed, accuracy, and automation from concept to manufacturing.