Family placement only works with first few families listed from window

Family placement only works with first few families listed from window

lrsmns
Enthusiast Enthusiast
810 Views
4 Replies
Message 1 of 5

Family placement only works with first few families listed from window

lrsmns
Enthusiast
Enthusiast

Hello,

 

I have a list of families displayed in my modeless window that can be selected to be placed.

However the placement only works on several first families, it doesn work on the rest of the family.

The inconsistency is still a mistery for me... it's not catching any error. I'm not quiet sure what kind of error type this is or how to look for

This is what i have so far,

My External Command:

[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
[Journaling(JournalingMode.NoCommandData)]

public class PlaceFamilyCmd : IExternalCommand
{
    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
        try
        {
            string Parameter = "CategoryName";
            var uiApp = commandData.Application;
            var m = new FamilyLibraryModel(uiApp);
            var vm = new FamilyLibraryViewModel(m, Parameter, uiApp);
            var v = new FamilyLibraryView()
            {
                DataContext = vm
            };

            //pairing with revit window, so it minimizes and closes together
            var unused = new WindowInteropHelper(v)
            {
                Owner = Process.GetCurrentProcess().MainWindowHandle
            };

            v.Show();

            return Result.Succeeded;
        }
        catch (Exception e)
        {
            TaskDialog.Show("Error", e.ToString());
            message = e.Message;
            return Result.Failed;
        }
    }
}

My Model class:

public class FamilyLibraryModel
{
    public UIApplication uiapp {  get; }
    public Document doc { get; }
    public UIDocument uidoc { get; }
    public FamilyLibraryModel(UIApplication uiApp)
    {
        uiapp = uiApp; 
        doc = uiApp.ActiveUIDocument.Document;
        uidoc = uiApp.ActiveUIDocument;

    }
    public ObservableCollection<RevitFamilyWrapper> CollectFurnitureObjects(string Parameter)
    {          
        var familySymbols = new FilteredElementCollector(doc)
                .OfClass(typeof(FamilySymbol))
                .Where(x => 
                x.LookupParameter("Parametername") != null &&
                x.LookupParameter("Parametername").HasValue &&
                x.LookupParameter("Parametername").AsString().Equals(Parameter))
                .Cast<FamilySymbol>()
                .Select(x => new RevitFamilyWrapper(x));
       

        return new ObservableCollection<RevitFamilyWrapper>(familySymbols);
    }

          
}

My Wrapper class:

public class FamilyWrapper : INotifyPropertyChanged
{
    public string familyNameAndTypeName { get; set; }
    public ElementType familyElementType { get; set; }
    public Bitmap familyThumbnail { get; set; }
    public Size size { get; set; }
    public FamilySymbol familySymbol { get; }

    private bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set { _isSelected = value; RaisePropertyChanged(nameof(IsSelected)); }
    }

    public FamilyWrapper(FamilySymbol familySymb)
    {
        familySymbol = familySymb;
        familyNameAndTypeName = familySymb.FamilyName + " " + familySymb.Name;
        familyElementType = familySymb as ElementType;
        size = new Size(80, 80);
        familyThumbnail = familyElementType.GetPreviewImage(size);

    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

 

 

My View Model Class:

public class FamilyLibraryViewModel : ObservableObject
{
    public FamilyLibraryModel Model { get; set; }
    public RelayCommand<Window> Place { get; set; }
    public string Kategorie { get; set; }
    public Document Doc { get; }
    public ExternalEvent PlaceFamilyEvent { get; set; }
    public PlaceFamilyHandler PlaceFamilyHandler { get; set; }

    private ObservableCollection<RevitFamilyWrapper> _furnitures; 
    public ObservableCollection<RevitFamilyWrapper> Furnitures
    {
        get => _furnitures;
        set => SetProperty(ref _furnitures, value);
    }

    public FamilyLibraryViewModel(FamilyLibraryModel model, string parameter, UIApplication uiApp)
    {
        Model = model;
        Furnitures = Model.CollectFurnitureObjects(parameter);
        Kategorie = parameter;

        PlaceFamilyHandler = new PlaceFamilyHandler { UiApp = uiApp };
        PlaceFamilyEvent = ExternalEvent.Create(PlaceFamilyHandler);

        Place = new RelayCommand<Window>(OnPlace);
    }

    private void OnPlace(Window window)
    {
        var selected = Furnitures.Where(x => x.IsSelected).ToArray();
        PlaceFamilyHandler.SelectedFamilies = selected;
        PlaceFamilyEvent.Raise();
        window.Close();
    }
}

 

My Event Handler:

public class PlaceFamilyHandler : IExternalEventHandler
{
    public IEnumerable<FamilyWrapper> SelectedFamilies { get; set; }
    public UIApplication UiApp { get; set; }
     
    public void Execute(UIApplication app)
    {
        var doc = UiApp.ActiveUIDocument.Document;
        var uidoc = UiApp.ActiveUIDocument;
        var selectedFamilySymbol = SelectedFamilies.Select(x => x.familySymbol).FirstOrDefault();

        if (selectedFamilySymbol != null)
        {
            using (var trans = new Transaction(doc, "Place Family"))
            {
                try
                {                        
                    uidoc.PromptForFamilyInstancePlacement(selectedFamilySymbol);                       
                }
                catch (Exception e) 
                {
                    TaskDialog.Show("Error", e.ToString());
                }
                
            }
        }
    }

    public string GetName()
    {
        return "Place Family Event";
    }
}

And my window xaml:

<Window
    x:Name="Win"
    x:Class="Revit.FamilyLibraryView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Name"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    SizeToContent="Height"
    Width="400"
    Title="Family Library
    WindowStartupLocation="Manual"
    BorderThickness="0,5,0,0"
    BorderBrush="Navy">
    <Window.Resources>
        <Style x:Key="DefaultRowStyle" TargetType="{x:Type DataGridRow}">
            <Setter Property="IsSelected" Value="{Binding IsSelected}"></Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <DataGrid ItemsSource="{Binding Furnitures, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                  RowStyle="{StaticResource DefaultRowStyle}"
                  AutoGenerateColumns="False"
                  VerticalScrollBarVisibility="Auto"
                  HorizontalScrollBarVisibility="Auto"
                  CanUserAddRows="False"
                  CanUserResizeColumns="False"
                  IsReadOnly="False"
                  SelectionMode="Single"
                  SelectionUnit="FullRow"
                  MaxHeight="400"
                  Margin="10">
            <DataGrid.Columns>
                <DataGridTextColumn Header="{Binding Kategorie, Mode=TwoWay}"
                                    Binding="{Binding familyNameAndTypeName, Mode=OneWay}"
                                    Width="*"
                                    IsReadOnly="True"/>

            </DataGrid.Columns>
        </DataGrid>
        <Button Grid.Row="1"
                Width="75"
                Height="20"
                HorizontalAlignment="Right"
                VerticalAlignment="Center"
                Margin="0,0,12,0"
                Content="Place"
                Command="{Binding Place, Mode=TwoWay}"
                CommandParameter="{Binding ElementName=Win}"/>
    </Grid>
</Window>

 Any insights will be appreciated! Thank you 🙂

0 Likes
Accepted solutions (1)
811 Views
4 Replies
Replies (4)
Message 2 of 5

lrsmns
Enthusiast
Enthusiast

So what i have noticed that for certain elements, if they get selected, they dont get into the wrapper.. which i'm not sure why that is possible

0 Likes
Message 3 of 5

Moustafa_K
Advisor
Advisor
Accepted solution

well it is a bit hard to say, but my 50 cent for this, there is a probability the IsSelected is not triggered, thus, the PlaceHandler will have nothing to place.

 

I would also prefer to have a complete isolation between the UI "Window" and your ViewModel. Meaning, I would suggest:

  1. give your DataGrid a name say x:Name="familyDataGrid"
  2. Bind the Button command Parameter to the SelectedItem of the familyDataGrid
    1. don't forget to change the RelayCommand to be RelayCommand<FamilyWrapper>
  3. now if you want close the window on hitting the button, just set a value to Click event, and close it from the window it self, this will ensure a better isolation in your design pattern

 

 <DataGrid x:Name="familyDataGrid" ItemsSource="{Binding Furnitures, Mode=TwoWay, ....
.....
...
..
. 
<Button Grid.Row="1"
                Width= "75"
                Height= "20"
                Click="Close_Window"
                HorizontalAlignment= "Right"
                VerticalAlignment= "Center"
                Margin= "0,0,12,0"
                Content= "Place"
                Command= "{Binding Place, Mode=TwoWay}"
                CommandParameter= "{Binding SelectedItem, ElementName=familyDataGrid}" />

 

Let us know how it goes.

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 4 of 5

TripleM-Dev.net
Advisor
Advisor

Hi @lrsmns,

 

If this happens in different x-times when using the app, it's propably because not all families were activated in the Project.

 

If a Family(symbol) was already used in the session it's already activated else it's not.

Before placing the family check if it activated with: IsActive Property if not then activate it  first with: Activate Method

 

The activate method need to be placed within a transaction, I'm not sure if placing the family can be called within the same transaction.

 

- Michel

0 Likes
Message 5 of 5

lrsmns
Enthusiast
Enthusiast

I eventually changed from data grid to listbox, and also used binding with SelectedItem.. now the binding works perfectly 🙂

 <ListBox ItemsSource="{Binding Furnitures, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
           Grid.Row="1"
           SelectionMode="Single"
           HorizontalAlignment="Stretch"
           VerticalAlignment="Stretch"
           Margin="10"
           SelectedItem="{Binding SelectedFamily, Mode=TwoWay}">
     ...
 </ListBox>
0 Likes