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?");
}
}