Community
Civil 3D Customization
Welcome to Autodesk’s AutoCAD Civil 3D Forums. Share your knowledge, ask questions, and explore popular AutoCAD Civil 3D Customization topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Programmatically Edit Multiple Object Styles?

7 REPLIES 7
Reply
Message 1 of 8
SteveMazza4062
872 Views, 7 Replies

Programmatically Edit Multiple Object Styles?

Hello all.  I am a fairly experienced user of Civil 3D with some programming background in LISP.  I have a vague idea of .NET programming, but no experience to speak of.  At my office, we use Civil 3D as a design tool, and sometimes in the finished (plotted) product.  We use STB (named) plot styles and layer settings to control object display.

 

I have a situation where I have received a drawing that is populated with Civil 3D styles already.  However, in the Display tab, all the object Plot Styles are set to ByBlock.  That does not seem to work properly with .STB plot style management, because the individual objects (contours, points, etc.) pick up the plot styles of their parent objects.  So instead of a contour on layer V-TOPO-MAJR plotting with the layer settings of V-TOPO-MAJR, it follows the layer settings of C-TOPO, which is the layer containing the parent surface.

 

Is there a way to programmatically step through styles for surfaces, profile views, etc. and change the "ByBlock" setting to "ByLayer" in all styles?

 

That would save me a lot of time.  I would also welcome the opportunity to learn a bit more about .NET.

 

Thanks in advance.

7 REPLIES 7
Message 2 of 8
Jeff_M
in reply to: SteveMazza4062

Yes, it can be done with the .NET API. Start with the Sample project "C:\Program Files\Autodesk\AutoCAD Civil 3D 2013\Sample\Civil 3D API\DotNet\CSharp\CompareStyles". It shows how to quickly loop through the styles. Each style has a type of DisplayStyle attached to it. So, for instance, to get those used by a SurfaceStyle there are 3:

Public method GetDisplayStyleModel
Gets the DisplayStyle object that specifies the surface component Model display color, layer, linetype, etc.
Public method GetDisplayStylePlan
Gets the DisplayStyle object that specifies the surface component Plan display color, layer, linetype, etc.
Public method GetDisplayStyleSection
Gets the DisplayStyle object that specifies the surface component Section display color, layer, linetype, etc.
 
 

With the display style you can loop through each of it's settings and change it's PlotStyle property, which is a String.

Jeff_M, also a frequent Swamper
EESignature
Message 3 of 8
mfernandes
in reply to: Jeff_M

Hey Jeff

In the CompareStyles.cs code, It seem that at this section of code that the styles obj is obtained i.e. "stylebase"

            foreach ( ObjectId sbid in scBase ) {
                StyleBase stylebase = ts.GetObject(sbid, OpenMode.ForRead) as StyleBase;

                // Add the style name and parameters to the list of all styles
                StyleInfo styleinfo = new StyleInfo();
                styleinfo.name = stylebase.Name;
                styleinfo.type = stylebase.GetType().ToString();
                // Get all the properties
                Type styleType = stylebase.GetType();
                PropertyInfo[] properties = styleType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);

 

 

I need some help.

How can I now drill down to get the layer name?

 

It will be different for a label as in a label you will have only one layer whereas in a C3D obj like an alignment there could be multipal layers.

 

Thanks, any help is always appreciated.

Message 4 of 8
Jeff_M
in reply to: mfernandes

I never figured out a way to do this using reflection so I created methods for every object style, with each method (39 right now) accepting different style type as an argument. I also modified the StyleInfo class to hold the information.

        
private static void GetDisplayStyles(AlignmentStyle style, ref StyleInfo styleinfo) { DisplayStyle ds = null; foreach (AlignmentDisplayStyleType dst in Enum.GetValues(typeof(AlignmentDisplayStyleType))) { ds = style.GetDisplayStyleModel(dst); styleinfo.DispStyleType.Add("Model - " + dst.ToString()); styleinfo.Layer.Add(ds.Layer); styleinfo.DisplayStyle.Add(ds); ds = style.GetDisplayStylePlan(dst); styleinfo.DispStyleType.Add("Plan - " + dst.ToString()); styleinfo.Layer.Add(ds.Layer); styleinfo.DisplayStyle.Add(ds); } ds = style.GetDisplayStyleSection(); styleinfo.DispStyleType.Add("Section"); styleinfo.Layer.Add(ds.Layer); styleinfo.DisplayStyle.Add(ds); ds = style.GetLineMarkerDisplayStyleSection(); styleinfo.DispStyleType.Add("SectionLineMarker"); styleinfo.Layer.Add(ds.Layer); styleinfo.DisplayStyle.Add(ds); } /// <summary> /// A class to store style information /// </summary> public class StyleInfo { public String parent; // Name of the collection holding the style public String name; // Name of the style public ObjectId oID; // Style ObjectId public List<String> DispStyleType = new List<string>(); public List<String> Layer = new List<string>(); public List<String> TextStyle = new List<string>(); public List<String> NestedTextLayer = new List<string>(); public List<String> NestedTextStyle = new List<string>(); public List<String> NestedLabelObj = new List<string>(); public List<DisplayStyle> DisplayStyle = new List<DisplayStyle>(); public List<ObjectId> NestedObjectId = new List<ObjectId>(); }

And I call the appropriate one with  switch() (this may be able to handled better, but it worked for me at the time as I was learning):

 switch (objecttype.Name)
                            {
                                case "FeatureLineStyle":
                                    GetDisplayStyles((FeatureLineStyle)stylebase, ref styleinfo);
                                    break;                               
                                case "AlignmentStyle":
                                    GetDisplayStyles((AlignmentStyle)stylebase, ref styleinfo);
                                    break;
                                //etc.
    }
Jeff_M, also a frequent Swamper
EESignature
Message 5 of 8
mfernandes
in reply to: Jeff_M

Ay, caramba Jeff !!!!!!

39 objects that is a lot of code. Kudos for sticking with it.

 a couple of questions,

 

1. for an alignment I see that there is layers for Plan, Model and Section. so what is this line of code for

ds = style.GetLineMarkerDisplayStyleSection()

styleinfo.Layer.Add(ds.Layer);

 

I assume all the markers will go on this layer, but is that not controlled by the marker style.

 

2.Given that Alignment as well as Profile in additional to other styles will also have "Plan, Model and Section" layers

is there a way I could generalize this line of code?

foreach (AlignmentDisplayStyleType dst in Enum.GetValues(typeof(AlignmentDisplayStyleType)))

Just learning C# so woundering if there is an ability to use a while loop or use something like

foreach (ObjDisplayStyleType dst in Enum.GetValues(typeof(ObjDisplayStyleType)))

 

Message 6 of 8
Jeff_M
in reply to: mfernandes


@mfernandes wrote:

 

1. for an alignment I see that there is layers for Plan, Model and Section. so what is this line of code for

ds = style.GetLineMarkerDisplayStyleSection()

styleinfo.Layer.Add(ds.Layer);

 

I assume all the markers will go on this layer, but is that not controlled by the marker style.

That part of the code is getting this setting:

9-3-2015 2-42-26 PM.png

 

2.Given that Alignment as well as Profile in additional to other styles will also have "Plan, Model and Section" layers

is there a way I could generalize this line of code?

foreach (AlignmentDisplayStyleType dst in Enum.GetValues(typeof(AlignmentDisplayStyleType)))

Just learning C# so woundering if there is an ability to use a while loop or use something like

foreach (ObjDisplayStyleType dst in Enum.GetValues(typeof(ObjDisplayStyleType)))

 Yes, it would be nice if it were that simple. But, as I said, I never found a better way of doing it. Not all styles have Plan, Profile, Section, and Model display styles. Some have just Plan, others Plan and Model, and so on. And I needed to know which Type so I could present it that way to the user. I'm sure there is a better way, I just don't know what it may be.... Smiley Frustrated Feel free to share if you find it. Smiley Very Happy


 

Jeff_M, also a frequent Swamper
EESignature
Message 7 of 8

Here is a Reflection approach to reach all "GetDisplay" methods to read the layers

 

public static class ExntesionMethods
{
  public static List<string> GetDisplayStyleLayer(this StyleBase style)
  {
    // layers found
    List<string> layers = new List<string>();
    // get all methods that contains "GetDisplay" on their names
    var methods = style.GetType().GetMethods().Where(m => m.Name.Contains("GetDisplay"));
    // run through the collection of methods
    foreach (MethodInfo method in methods)
    {
      if (method.GetParameters().Length != 1) continue; // if not 1, then we don't know
      ParameterInfo param = method.GetParameters()[0];
      if (!param.ParameterType.IsEnum) continue; // not a enum, skip
      // check all values on the enum
      foreach (var enumValue in Enum.GetValues(param.ParameterType))
      {
        DisplayStyle dispStyle = method.Invoke(style, new object[] { enumValue }) as DisplayStyle;
        if (dispStyle == null) continue;// something went wrong
        layers.Add(dispStyle.Layer); // get the layer name
      }
    }
    return layers;
  }
}

 

And a testing method:

 

// test code
[CommandMethod("getLayersFromDisplayStyle")]
public static void CmdGetLayers()
{
  CivilDocument civilDoc = CivilApplication.ActiveDocument;
  using (Transaction trans = Application.DocumentManager.MdiActiveDocument.Database.TransactionManager.StartTransaction())
  {
    StyleBase st = trans.GetObject(civilDoc.Styles.AlignmentStyles[0], OpenMode.ForRead) as StyleBase;
    List<string> res = st.GetDisplayStyleLayer();
  }
}
Regards,



Augusto Goncalves
Twitter @augustomaia
Autodesk Developer Network
Message 8 of 8
Jeff_M
in reply to: augusto.goncalves

@augusto.goncalves, Thank you for posting the Reflection code for the DIsplayStyles. I now have this working for my app and all styles are now gathered without all the manually created overloads I had done. I had tried to create this years ago but was hampered by my limited knowledge of how to use Reflection. After seeing your code, and comparing to what I had been working on back then, I was actually quite close to getting it working. But having spent too much time on it I abandoned it in favor of the manual approach.

 

Now for the downside...you knew there had to be one, right? There are 2 issues using this code. The first is that two TableStyle types throw a TargetInvocation error when getting their display styles. This error can be handled with a Try/Catch. I added some code to output all of the styles to a file in order to easily see what is, or isn't, working. Here's the results of 3 TableStyles, one of which works fine.

 

Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: Border
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: TitleSeparator
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: HeaderSeparator
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: DataSeparator
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: DataDivider
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: TitleAreaFill
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: HeaderAreaFill
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: DataAreaFill
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: TitleText
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: HeaderText
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewMaterial throws an error on Enum: DataText
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - Border - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - TitleSeparator - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - HeaderSeparator - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - DataSeparator - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - DataDivider - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - TitleAreaFill - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - HeaderAreaFill - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - DataAreaFill - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - TitleText - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - HeaderText - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle - Basic - DataText - 0;
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: Border
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: TitleSeparator
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: HeaderSeparator
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: DataSeparator
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: DataDivider
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: TitleAreaFill
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: HeaderAreaFill
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: DataAreaFill
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: TitleText
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: HeaderText
Autodesk.Civil.DatabaseServices.Styles.TableStyle SectionViewTotalVolume throws an error on Enum: DataText

 

The other issue is a bit worse, in that it crashes Civil3d. A Try/Catch does not handle it. This is that the ProfileView/BandStyles/Horizontal Geometry styles have 3 DisplayStyles that Fatal Error when the Layer property is accessed. These 3 items do not show up in the Style editor, so probably should be omitted from the product. I added the following array to look in so I can skip over them in the code:

             string[] badEnums = {"TangentCurvature",
                                    "CurveCurvature",
                                    "SpiralCurvature"
                                };

 

Jeff_M, also a frequent Swamper
EESignature

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Rail Community


 

Autodesk Design & Make Report