python-2.7xamldata-bindingrevit-apipyrevit

Setting multiple ItemsSource for WPF from python class


Hi I am trying to populate a ComboBox and ListBox in a WPF application using PyRevit. The app runs fine with one of the WPF "Box's" obtaining an List though when I try to add both I get an error saying "unexpected indent". Below is what I am trying to achieve:

# dependencies

import os.path as op
import codecs
from collections import namedtuple

from System.Collections.Generic import List
from collections import OrderedDict
from operator import getitem

from pyrevit import HOST_APP
from pyrevit import USER_DESKTOP
from pyrevit import framework
from pyrevit.framework import Windows, Drawing, ObjectModel, Forms
from pyrevit import coreutils
from pyrevit import forms
from pyrevit import revit, DB
from pyrevit import script
import sys
import threading
from pyrevit import EXEC_PARAMS

import clr
clr.AddReference('System.Windows.Forms')
clr.AddReference('IronPython.Wpf')

from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import *
from Autodesk.Revit.DB.Analysis import *

# find the path of ui.xaml
from pyrevit import UI

doc = __revit__.ActiveUIDocument.Document

#loggers
logger = script.get_logger()
output = script.get_output()

#Collectors
cmbPrimary = []
lbxViews = []
viewPortList = []
lbxViewsSorted = []

#Get all viewports in Document
viewPorts = list(DB.FilteredElementCollector(doc).OfClass(Viewport))


#Get all Views on sheets, their Name, Sheet Number and Box Outline
for vp in viewPorts:
    sheet = doc.GetElement(vp.SheetId)
    view = doc.GetElement(vp.ViewId)
    vbox = vp.GetBoxOutline()
    viewPortList.append([sheet.SheetNumber, view.ViewName, vbox])

lbxViewsSorted = sorted(viewPortList, key=lambda x: x[0])

for vp in lbxViewsSorted:
    lbxViews.append(vp[0] + " , " + vp[1])
    cmbPrimary.append(vp[0] + " , " + vp[1])

#Create View Model
class ViewModel(forms.Reactive):
    def __init__(self): 
        self.ViewPorts = lbxViews
        self.primaryView = cmbPrimary

# code for the window
class MyWindow(forms.WPFWindow, forms.Reactive):
    def __init__(self):
        self.vm = ViewModel()
    
    def setup(self):
        self.lbxViews.ItemsSource = self.vm.ViewPorts
        self.cmbPrimary.ItemsSource = self.vm.primaryView

# init ui
ui = script.load_ui(MyWindow(), 'ui.xaml')
# show modal or nonmodal
ui.show_dialog()

This only works when I only try to populate one the WPF containers, below is just the ListBox and not the ComboBox:

def setup(self):
    self.lbxViews.ItemsSource = self.vm.ViewPorts

The XAML is as follows:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Align Views"
        Width="350" ResizeMode="NoResize" Height="800">
    <StackPanel Margin="10,10,10,10">
        <Label Content="Select view to align to:" Margin="0,0,0,10" />
        <ComboBox x:Name="cmbPrimary" ItemsSource="{Binding cmbPrimary}"/>
        <Label Content="Select views to align:" Margin="0,0,0,10" />
        <ListBox x:Name="lbxViews" Height="450" ItemsSource="{Binding lbxViews}" SelectionMode="Extended" />
        <Label Content="Select alignment point:" Margin="0,0,0,10" />
        <ComboBox x:Name="cmbAlignment"/>
        <StackPanel Margin="8" Orientation="Horizontal">
            <Button x:Name="btnOK" MinWidth="93">OK</Button>
            <Button x:Name="btnCancel" MinWidth="93" Margin="10,0,0,0">Cancel</Button>
        </StackPanel>
    </StackPanel>
    
</Window>

I probably need to use DataContext I presume? But not sure if its a pythonic or WPFonic issue. Any help would be appreciated! Thanks!


Solution

  • I figured it out. The code is fine I had an unnecessary indent within

    def setup
    

    All good!