Single Line Text to Multiline Text

This is one of my favorite Revit Macros. It matches the functionality of the Autocad "Text to Multiline Text" command, or "TXT2MTXT". It takes individual text notes and combines them into a one multiline text note. Text is placed in order from top to bottom, and left to right.

public void Txt2MTxt()

{

//02/13/2019 by swr

// converts single line text to multiline text

// places text in order top to bottom

// if more than 1 text note is at the same height, it combines left to right, then top to bottom

UIDocument uidoc = this.ActiveUIDocument; //dont need this

Document doc = this.ActiveUIDocument.Document;

// Get the element selection of current document

Selection selection = uidoc.Selection;


//store element id's

ICollection<ElementId> selectedIds = uidoc.Selection.GetElementIds();

// Make a list for holding items that are not text notes, so they are not deleted

List<ElementId> mylist = new List<ElementId>();

ICollection<ElementId> notTextIds = mylist;

//Create a dictonary for the selected text items and their y positions -- Updated on 2/13 to use lists of tuples instead of dictonaries

// y position is the key, and x postion is the value

// Dictionary<double, string> TextData = new Dictionary<double, string> ();

//create a list of tuples to hold the values for Y position, X position, and the string contents of the note

var tupleList = new List<Tuple<double, double, string>>

{

//Tuple.Create( 1.0, 1.0, "cow" ), // from examples on initializing a list of tuples

//Tuple.Create( 5.0, 5.0, "chickens" ),

//Tuple.Create( 1.0, 1.0,"airplane" )

};


//Create another dictonary for the text locations X&Y;

//Y position is the key, and x position is the value

//Dictionary<double, double> TextLoc = new Dictionary<double, double> ();

// go through each selected item;

int n = 0;

foreach (ElementId id in selectedIds) //for each selected element


{

Element e = doc.GetElement(id); //get the element from the id

//TaskDialog.Show("Revit",e.Name.ToString());

//TaskDialog.Show("Revit",e.GetTypeId().GetType().ToString());

try

{

//Get the text parameter and the text contained in the parameter

Parameter MyTextParam = e.get_Parameter(BuiltInParameter.TEXT_TEXT);

string MyText = MyTextParam.AsString();


//cast the element as a TextNote so the coordinates can be obtained;

TextNote T = e as TextNote;

XYZ TEXT_LOCATION = T.Coord as XYZ;

double myX = (TEXT_LOCATION.X);

double myY = (TEXT_LOCATION.Y);

//TaskDialog.Show("REvit", myX.ToString () + "\n\r" + myY.ToString() + "\n\r" + MyText);

// add the location and string to the list of tuples

tupleList.Add(Tuple.Create( myY, myX, MyText));

}

//if an item is not a text note, it should be caught here

catch

{

notTextIds.Add(id);

n = n+1;

}// end catch

}// end foreach

// sort both dictionaries per position: -----------------------------

// var sortedText = from entry in TextData orderby entry.Key descending select entry;

// var sortedLoc = from entry in TextData orderby entry.Key descending select entry;

//var sortedlist = from entry in tupleList orderby descending select entry;

tupleList.Sort((t2, t1) => {

int c = t1.Item1.CompareTo(t2.Item1);

if (c != 0) return c;

c = t1.Item2.CompareTo(t2.Item2);

return -c;

}

);

//place each line of text in a string in order

string mystring = null;

//foreach(KeyValuePair<double, string> entry in sortedText )

foreach (Tuple<double, double, string> t in tupleList )

{

mystring = mystring + t.Item3;

}

//TaskDialog.Show("Revit", mystring);

// find location of top text note:

var first = tupleList[0];

double Texty = first.Item1;

double Textx = first.Item2;

//create a new text note:


using (Transaction tran = new Transaction(doc, "Text to Multiline Text"))

{

XYZ origin = new XYZ(Textx, Texty, 0);

ElementId defaultTypeId = doc.GetDefaultElementTypeId(ElementTypeGroup.TextNoteType);

tran.Start();

TextNote note = TextNote.Create(doc, doc.ActiveView.Id, origin, mystring, defaultTypeId);

//once the new note is placed, the single line notes can be deleted:

ICollection<ElementId> elements = uidoc.Selection.GetElementIds();

// first remove the non-text items from the list

foreach (ElementId id in notTextIds )

{

elements.Remove (id);

}

ICollection<Autodesk.Revit.DB.ElementId> deletedIdSet = doc.Delete(elements);


tran.Commit();

} // end using

if (n>0)

{TaskDialog.Show("Text to MText Error" , "Revit did not include " + n.ToString () + " items."

+ "\n\r" + "Did you select non-text items?");

}


}