The two main differences between VB and C# are syntax and strictness (while VB option 'strict' is off which is the default).C# is more strongly typed and allows less implicit casts.

KeepAttributesHorizontal - Lesson 1 CompletedOnly syntax differences with the VB code.Prefixing the class fields with an underscore is not requiered (it's only a convention as using 'my*' in VB languages).

[CommandMethod("KeepStraight")] public static void ImplementOverrule() { // We only want to create our overrule instance once, // so we check if it already exists before we create it // (i.e. this may be the 2nd time we've run the command) if (_overrule == null) { // Instantiate our overrule class _overrule = new KeepStraightOverrule(); // Register the overrule Overrule.AddOverrule (RXClass.GetClass(typeof(AttributeReference)), _overrule, false); } // Make sure overruling is turned on so our overrule works Overrule.Overruling = true; } }

' Open the BlockReference for read. ' We know its a BlockReference because we set a filter in ' our PromptEntityOptions Dim blkRef As BlockReference = trans.GetObject(res.ObjectId, OpenMode.ForRead) ' Record the ObjectIds of all AttributeReferences ' attached to the BlockReference. Dim attRefColl As AttributeCollection = blkRef.AttributeCollection ReDim objIds(attRefColl.Count) attRefColl.CopyTo(objIds, 0) ReDim Preserve objIds(attRefColl.Count - 1) End Using

'We only want to create our overrule instance once, ' so we check if it already exists before we create it ' (i.e. this may be the 2nd time we've run the command) If myOverrule Is Nothing Then 'Instantiate our overrule class myOverrule = New KeepStraightOverrule 'Register the overrule Overrule.AddOverrule( RXClass.GetClass(GetType(AttributeReference)), myOverrule, False) End If

'Specify which Attributes will be overruled myOverrule.SetIdFilter(objIds)

'Make sure overruling is turned on so our overrule works Overrule.Overruling = True

'We want to change how an AttributeReference responds to being ' transformed (moved, rotated, etc.), so we override its ' standard TransformBy function. Public Overrides Sub TransformBy(ByVal entity As Entity, ByVal transform As Matrix3d)

'Call the normal TransformBy function for the attribute ' reference we're overruling. MyBase.TransformBy(entity, transform) 'We know entity must be an AttributeReference because ' that is the only entity we registered the overrule for. Dim attRef As AttributeReference = entity 'Set rotation of attribute reference to 0 (horizontal) attRef.Rotation = 0.0

using (Transaction trans = db.TransactionManager.StartTransaction()) { // Open the BlockReference for read. // We know its a BlockReference because we set a filter in // our PromptEntityOptions. BlockReference blkRef = (BlockReference)trans.GetObject(res.ObjectId, OpenMode.ForRead); // Record the ObjectIds of all AttributeReferences // attached to the BlockReference. AttributeCollection attRefColl = blkRef.AttributeCollection;

using (Transaction trans = db.TransactionManager.StartTransaction()) { // Open the BlockReference for read. // We know its a BlockReference because we set a filter in // our PromptEntityOptions. BlockReference blkRef = (BlockReference)trans.GetObject(res.ObjectId, OpenMode.ForRead); // Record the ObjectIds of all AttributeReferences // attached to the BlockReference. AttributeCollection attRefColl = blkRef.AttributeCollection;

[CommandMethod("ActivateOverrule")] private static void ActivateOverrule() { // We only want to create our overrule instance once, // so we check if it already exists before we create it // (i.e. this may be the 2nd time we've run the command) if (_overrule == null) { // Instantiate our overrule class _overrule = new KeepStraightOverrule(); // Register the overrule Overrule.AddOverrule (RXClass.GetClass(typeof(AttributeReference)), _overrule, false); } // Specify which Attributes will be overruled _overrule.SetXDataFilter(_regAppName); // Make sure overruling is turned on so our overrule works Overrule.Overruling = true; }

// Create new xdata containing the overrule filter name using (ResultBuffer resBuf = new ResultBuffer( new TypedValue((int)DxfCode.ExtendedDataRegAppName, regAppName))) { // Add the xdata // Because we leave this blank except for the regappid, // it erases any Xdata we previously added. AddXdata(res.ObjectId, resBuf, db); } }

[CommandMethod("ActivateBillboardOverrule")] public static void ActivateOverrule() { // We only want to create our overrule instance once, // so we check if it already exists before we create it // (i.e. this may be the 2nd time we've run the command) if (_overrule == null) { // Instantiate our overrule class _overrule = new BillboardAttributesOverrule(); // Register the overrule Overrule.AddOverrule (RXClass.GetClass(typeof(AttributeReference)), _overrule, false); } // Specify which Attributes will be overruled _overrule.SetXDataFilter(regAppName); // Make sure overruling is turned on so our overrule works Overrule.Overruling = true; }

// Open the BlockReference for read. // We know its a BlockReference because we set a filter in // our PromptEntityOptions. BlockReference blkRef = (BlockReference)trans.GetObject(id, OpenMode.ForRead); // Record the ObjectIds of all AttributeReferences // attached to the BlockReference. AttributeCollection attRefColl = blkRef.AttributeCollection;

I updated the code of the 'Bonus Plugin'.I re-write the origin point definition used in the transformation matrix calculation of the BillboardAttributesOverrule.ViewportDraw() method so that it works whatever the attribute text justification.