Hi,
I'm trying to create a UI where we can select a family and prompt to place it.
This is the OnPlace method that is made for the place button:
private void OnPlace(Window window)
{
var selected = Furnitures.Where(x => x.IsSelected).ToArray();
Model.Place(selected);
window.Close();
}
The method Place from line 4 is defined here under...
I managed to get the selected item as defined in my wrapper, however i have difficulties in querying just the family symbol from my wrapper (see line 3):
public void Place(IEnumerable<RevitFamilyWrapper> selected)
{
var selectedFamilySymbolEnum = selected.Select(x=>x.familySymbol);
var selectedFamilySymbol = selectedFamilySymbolEnum as FamilySymbol;
using (var trans = new Transaction((doc), "Place Family"))
{
trans.Start();
uidoc.PromptForFamilyInstancePlacement(selectedFamilySymbol);
trans.Commit();
}
}
This is my family wrapper:
public class RevitFamilyWrapper : INotifyPropertyChanged
{
public string familyNameAndTypeName { get; set; }
public ElementType familyElementType { get; set; }
public FamilySymbol familySymbol { get; }
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set { _isSelected = value; RaisePropertyChanged(nameof(IsSelected)); }
}
public RevitFamilyWrapper(FamilySymbol familySymb)
{
familySymbol = familySymb;
familyNameAndTypeName = familySymb.FamilyName + " " + familySymb.Name;
familyElementType = familySymb as ElementType;
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Would appreciate any insights!
This line looks wrong.
var selectedFamilySymbol = selectedFamilySymbolEnum as FamilySymbol;
You cannot convert a collection of item in a single one like that.
Using First() would make more sense, to select the first item in the collection.
var selectedFamilySymbol = selectedFamilySymbolEnum.First();
I guess would make more sense to the Place method to allow only one family.
public void Place(RevitFamilyWrapper selected)
{
var selectedFamilySymbol = selected.familySymbol;
using (var trans = new Transaction((doc), "Place Family"))
{
trans.Start();
uidoc.PromptForFamilyInstancePlacement(selectedFamilySymbol);
trans.Commit();
}
}
And use First in the OnPlace.
private void OnPlace(Window window)
{
var selected = Furnitures.Where(x => x.IsSelected).First();
Model.Place(selected);
window.Close();
}
I don't know if you can select more the one family in the UI or is none selection as well, you need to handle that cases.
I have been developing a plugin to load and place family, here is the link of the project.
Thank you for the hint and your helpful resources!!
I have a further problem with the transactions, it says the following:
to which is followed that transactions outside the API is not permissible (?)
@lrsmns wrote:I have a further problem with the transactions, it says the following:
The PromptForFamilyInstancePlacement does not require a Transaction and looks like if shows an exception if you have a transaction opened.
@lrsmns wrote:to which is followed that transactions outside the API is not permissible (?)
If you are running that code in a modeless WPF you gonna receive that exception, you cannot call Revit API methods anywhere you want. Need to be in the main Thread and in the time Revit is ready, that's basically the Revit API Context.
There is the ExternalEvent/IExternalEventHandler that you need to use to run your code in Revit context.
Or you could use a library that manage the creation of the ExternalEvents and enable await to know what the code finished.
And here a resource about how to know if Revit API is in context.
Can't find what you're looking for? Ask the community or share your knowledge.