Thank you for the screen snapshots, explanation and updated code.
Do the stair railings have a different category than OST_Stairs? Apparently so.
Can you share a minimal sample model to run this in that demonstrates the problem?
Oh, and I still wonder: why do you break out of the loop after painting the first landing or run? Would you never want to paint two, or more, or all of them, if there are more than one?
Here is a cleaned up version of your code that I added to The Building Coder samples:
/// <summary>
/// Prompt user to pick a face and paint it
/// with the given material. If the face belongs
/// to a stair run or landing, paint that part
/// of the stair specifically.
/// </summary>
void PaintSelectedFace( UIDocument uidoc, Material mat )
{
Document doc = uidoc.Document;
Selection sel = uidoc.Selection;
List<String> errors = new List<string>();
//SurfaceSelectionFilter filter = new SurfaceSelectionFilter();
Reference pickedRef = sel.PickObject(
ObjectType.PointOnElement,
//filter,
"Please select a face to paint" );
Element elem = doc.GetElement( pickedRef );
GeometryObject geoObject = elem
.GetGeometryObjectFromReference( pickedRef );
Face selected_face = geoObject as Face;
using( Transaction transaction = new Transaction( doc ) )
{
transaction.Start( "Paint Selected Face" );
if( elem.Category.Id.IntegerValue.Equals(
(int) BuiltInCategory.OST_Stairs ) )
{
Stairs str = elem as Stairs;
bool IsLand = false;
ICollection<ElementId> landings = str.GetStairsLandings();
ICollection<ElementId> runs = str.GetStairsRuns();
foreach( ElementId id in landings )
{
Element land = doc.GetElement( id );
List<Solid> solids = GetElemSolids(
land.get_Geometry( new Options() ) );
IsLand = SolidsContainFace( solids, selected_face );
if( IsLand )
{
break;
}
}
if( IsLand )
{
foreach( ElementId id in landings )
{
doc.Paint( id, selected_face, mat.Id );
break;
}
}
else
{
foreach( ElementId id in runs )
{
doc.Paint( id, selected_face, mat.Id );
break;
}
}
}
else
{
try
{
doc.Paint( elem.Id, selected_face, mat.Id );
}
catch( Exception ex )
{
TaskDialog.Show( "Error painting selected face",
ex.Message );
}
}
transaction.Commit();
}
}
/// <summary>
/// Does the given face belong to one of the given solids?
/// </summary>
private bool SolidsContainFace( List<Solid> solids, Face face )
{
foreach( Solid s in solids )
{
if( null != s
&& 0 < s.Volume )
{
foreach( Face f in s.Faces )
{
if( f == face )
{
return true;
}
else if( f.HasRegions )
{
foreach( Face f2 in f.GetRegions() )
{
if( f2 == face )
{
return true;
}
}
}
}
}
}
return false;
}
/// <summary>
/// Recursively collect all solids
/// contained in the given element geomety
/// </summary>
List<Solid> GetElemSolids( GeometryElement geomElem )
{
List<Solid> solids = new List<Solid>();
if( null != geomElem )
{
foreach( GeometryObject geomObj in geomElem )
{
if( geomObj is Solid solid )
{
if( solid.Faces.Size > 0 )
{
solids.Add( solid );
continue;
}
}
if( geomObj is GeometryInstance geomInst )
{
solids.AddRange( GetElemSolids(
geomInst.GetInstanceGeometry() ) );
}
}
}
return solids;
}
Would you like to test that and check that I didn't break anything?