PreviewControlRevitAPI Python

Hello guys,

I found that OpenSource project but it is in C#. I could not manage to translate Classes into Python. Can someone take a look?

Thank you very much!

Hello @Deniz_Maral
very interesting

1 Like

Thank you very much Cyril! I had a problem with converting a lambda function that pass EventHandler activities. I tried it also in WinForm but it was an empty window.

Not sure if this could help, but seems to be in line.

GUI Basics: First “Hello World” WPF Window - YouTube

1 Like

Hello Sean,

thanks for sharing it but I know it already. I don’t know how to reference a Class in Windows Class that referenced in xaml.

1 Like

I took a look and it looks very interesting :v:

try this

import sys
import clr
import wpf
clr.AddReference("System.Xml")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")
import System
from System.IO import StringReader
from System.Xml import XmlReader

from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

#import Revit APIUI namespace
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument

class PreviewControlRevitAPI(Window):
	def __init__(self, xaml):
		#collecotr = FilteredElementCollector(doc).OfClass(DB.View)
		self._xaml = xaml	
		xr = XmlReader.Create(StringReader(self._xaml))
		self.winLoad = wpf.LoadComponent(self, xr)
		self._grid1 = self.winLoad.FindName('grid1')
		self._previewControl = PreviewControl(doc, doc.ActiveView.Id)
		self._previewControl.Loaded += self.PreviewControlLoaded
		self._grid1.Children.Add(self._previewControl)

		
	def PreviewControlLoaded(self, sender, e):
		self._previewControl.UIView.ZoomToFit()


xaml = """
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="Preview Control"
    Height="500"
    Width="500"
    ResizeMode="NoResize"
    mc:Ignorable="d">
    <Grid>
        <Grid
            Name="grid1"
            HorizontalAlignment="Left"
            VerticalAlignment="Top" />
    </Grid>
</Window>"""

preview = PreviewControlRevitAPI(xaml)
preview.ShowDialog()

OUT = 0

Note only works with IronPython, thanks @chuongpqvn for the repo

4 Likes

Oh my god! It works, merci Cyril!

I could not manage to manage that one…
self._previewControl.Loaded += self.PreviewControlLoaded
What does += or -= without a loop?

Are they async and await in C#?
https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/keywords/async

https://ironpython.net/documentation/dotnet/dotnet.html#accessing-net-events

1 Like
import sys
import clr
import wpf
clr.AddReference("System.Xml")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")
import System
from System.IO import StringReader
from System.Xml import XmlReader

from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

#import Revit APIUI namespace
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
output = []
class PreviewControlRevitAPI(Window):
	def __init__(self, xaml):
		views = FilteredElementCollector(doc) \
            .OfCategory(BuiltInCategory.OST_Views).WhereElementIsNotElementType() \
            .ToElements()
		view_names = [i.Name for i in views]
		self._xaml = xaml	
		xr = XmlReader.Create(StringReader(self._xaml))
		self.winLoad = wpf.LoadComponent(self, xr)
		self._grid1 = self.winLoad.FindName('grid1')

		self._previewControl = PreviewControl(doc, doc.ActiveView.Id)
		self._previewControl.Loaded += self.PreviewControlLoaded
		self._grid1.Children.Add(self._previewControl)
		self.viewNames.ItemsSource = view_names
		
	def changeView(self,sender,e):
		selectedView = self.viewNames.SelectedItem
		views = FilteredElementCollector(doc) \
            .OfCategory(BuiltInCategory.OST_Views).WhereElementIsNotElementType() \
            .ToElements()
		view_names = [i.Name for i in views]
		indexV = view_names.index(selectedView)
		idView = views[indexV]
		output.append(idView.Id)
		

		
	def PreviewControlLoaded(self, sender, e):
		self._previewControl.UIView.ZoomToFit()
		
		
		




		


xaml = """
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="Preview Control"
    Height="500"
    Width="500"
    ResizeMode="NoResize"
    mc:Ignorable="d">
     <DockPanel HorizontalAlignment="Stretch" DockPanel.Dock="Top">
     <StackPanel DockPanel.Dock="Top">
                <Label x:Name="prompt_lb" FontWeight="Bold" Padding="0,0,0,5">Ansicht auswählen</Label>
                <ComboBox x:Name="viewNames" SelectionChanged="changeView"
                      Height="30"
                      IsEditable="True"
                      FontSize="14"
                      VerticalContentAlignment="Center"
                      StaysOpenOnEdit="True"/>
            </StackPanel>
            
        <Grid
            Name="grid1"
            HorizontalAlignment="Left"
            VerticalAlignment="Top" />
          
    
    </DockPanel>
</Window>"""

preview = PreviewControlRevitAPI(xaml)
preview.ShowDialog()
OUT = output

I added a dropdown which you can select a view and switch to it but I get an error that I can only open one view. Which method can I use to change view? I got somehow ViewId but assigning it, I could not find the right function.

Ok I found the solution:

import sys
import clr
import wpf
clr.AddReference("System.Xml")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")
import System
from System.IO import StringReader
from System.Xml import XmlReader

from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

#import Revit APIUI namespace
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
output = []
class PreviewControlRevitAPI(Window):
	def __init__(self, xaml):
		views = FilteredElementCollector(doc) \
            .OfCategory(BuiltInCategory.OST_Views).WhereElementIsNotElementType() \
            .ToElements()
		view_names = [i.Name for i in views]
		self._xaml = xaml	
		xr = XmlReader.Create(StringReader(self._xaml))
		self.winLoad = wpf.LoadComponent(self, xr)
		self._grid1 = self.winLoad.FindName('grid1')

		self._previewControl = PreviewControl(doc, doc.ActiveView.Id)
		self._previewControl.Loaded += self.PreviewControlLoaded
		self._grid1.Children.Add(self._previewControl)
		self.viewNames.ItemsSource = view_names
		
	def changeView(self,sender,e):
		selectedView = self.viewNames.SelectedItem
		views = FilteredElementCollector(doc) \
            .OfCategory(BuiltInCategory.OST_Views).WhereElementIsNotElementType() \
            .ToElements()
		view_names = [i.Name for i in views]
		indexV = view_names.index(selectedView)
		idView = views[indexV]
		self._previewControl.Dispose()
		self._previewControl= PreviewControl(doc, idView.Id)
		self._grid1.Children.Add(self._previewControl)
		self._previewControl.Loaded += self.PreviewControlLoaded
		
		

		
	def PreviewControlLoaded(self, sender, e):
		self._previewControl.UIView.ZoomToFit()
		
		
		




		


xaml = """
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="Preview Control"
    Height="500"
    Width="500"
    ResizeMode="NoResize"
    mc:Ignorable="d">
     <DockPanel HorizontalAlignment="Stretch" DockPanel.Dock="Top">
     <StackPanel DockPanel.Dock="Top">
                <Label x:Name="prompt_lb" FontWeight="Bold" Padding="0,0,0,5">Ansicht auswählen</Label>
                <ComboBox x:Name="viewNames" SelectionChanged="changeView"
                      Height="30"
                      IsEditable="True"
                      FontSize="14"
                      VerticalContentAlignment="Center"
                      StaysOpenOnEdit="True"/>
            </StackPanel>
            
        <Grid
            Name="grid1"
            HorizontalAlignment="Left"
            VerticalAlignment="Top" />
          
    
    </DockPanel>
</Window>"""

preview = PreviewControlRevitAPI(xaml)
preview.ShowDialog()
OUT = output
2 Likes

@c.poupin how can I use variables of a method insinde of another method?
For example: In order to get views, I had to collect them again in changeView function. I created a new function and let’s say I want to get view_names from changeView. How can I do it in Python?

Would love to see a little movie clip or screenshots of your final product here @Deniz_Maral.

1 Like

use the ‘self’ keyword instance of the class

here some change
EDIT : code updated for compatibility with the 2 Pythons engines

import sys
import clr
clr.AddReference("System.Xml")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")
import System
from System.Collections.Generic import List
from System.IO import StringReader
from System.Xml import XmlReader
from System.Windows import LogicalTreeHelper 

from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

#import Revit APIUI namespace
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument

class PreviewControlRevitAPI(Window):
    def __init__(self, xaml):
        filterP = System.Predicate[System.Object](lambda x : not x.IsTemplate)
        self._views = List[Element](FilteredElementCollector(doc)\
                                        .OfCategory(BuiltInCategory.OST_Views)\
                                        .WhereElementIsNotElementType()\
                                        .ToElements())\
                                        .FindAll(filterP)
        self._dictView = {i.Name : i for i in self._views}
        self._xaml = xaml   
        xr = XmlReader.Create(StringReader(self._xaml))
        self.winLoad = XamlReader.Load(xr)        
        self._grid1 = LogicalTreeHelper.FindLogicalNode(self.winLoad, "grid1")
        self._previewControl = PreviewControl(doc, doc.ActiveView.Id)
        self._previewControl.Loaded += self.PreviewControlLoaded
        self._grid1.Children.Add(self._previewControl)
        self._viewNames = LogicalTreeHelper.FindLogicalNode(self.winLoad, "viewNames")
        self._viewNames.ItemsSource = sorted(self._dictView.keys())
        self._viewNames.SelectionChanged += self.changeView
        
    def changeView(self,sender,e):
        selectedViewName = sender.SelectedItem 
        idView = self._dictView.get(selectedViewName)
        self._previewControl.Dispose()
        self._previewControl= PreviewControl(doc, idView.Id)
        self._grid1.Children.Add(self._previewControl)
        self._previewControl.Loaded += self.PreviewControlLoaded

    def PreviewControlLoaded(self, sender, e):
        self._previewControl.UIView.ZoomToFit()


xaml = """
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="Preview Control"
    Height="800"
    Width="1200"
    ResizeMode="NoResize"
    mc:Ignorable="d">
     <DockPanel HorizontalAlignment="Stretch" DockPanel.Dock="Top">
     <StackPanel DockPanel.Dock="Top">
                <Label x:Name="prompt_lb" FontWeight="Bold" Padding="0,0,0,5">Select View to Show</Label>
                <ComboBox x:Name="viewNames"
                      Height="30"
                      IsEditable="True"
                      FontSize="14"
                      VerticalContentAlignment="Center"
                      StaysOpenOnEdit="True"/>
            </StackPanel>
            
        <Grid
            Name="grid1"
            HorizontalAlignment="Left"
            VerticalAlignment="Top" />
    </DockPanel>
</Window>"""

preview = PreviewControlRevitAPI(xaml)
preview.winLoad.Show()
OUT = 0

dynamicPreview4

2 Likes

Great tips! I added another combobox to select family and then try to get its views. My script works but I did not manage to write Class methods like you very clean.
If you select Family which is editable:
views = FilteredElementCollector(doc.EditFamily(fam)).OfClass(View)
self.viewNames.ItemsSource = new views

2 Likes

This is fantastic! However, much simple using C# :sweat_smile:

2 Likes

I meant: how can I for example use views var in change view in changeFamily method. I get always an error:
grafik

try this
image

1 Like

I update the code in my previous post for compatibility with the 2 Pythons engines
Not from Jealous :stuck_out_tongue_closed_eyes:

1 Like

and

saved my life :smiley: I was always wondering what sender does… Just perfect!

2 Likes