Creating a class to represent a CSS StyleSheet

A WindowsForms application I'm currently working on requires that the user can create their own StyleSheets.  The "StyleSheet" object is a collection of "Style" objects, much like a CSS StyleSheet contains a collection of CSS classes.  In fact, one requirement of this StyleSheet class is that it can be "serialized", so to speak, into an actual CSS file which can be attached to a webpage.  Of course, the serialization aspect is not the only purpose of this class as it will eventually be converted for use in multiple export formats (not of concern at this moment though.)

What I'm looking for here is the best way to structure the StyleSheet and Style classes so they can be converted to a CSS file with ease, while still remaining a very robust object.  As far as I'm aware, there is no class in the .NET Framework libraries that can be used to represent this (anything that there is using name/value pairs).  I need to be able to bind this object to a property grid as well as programmatically access many of it's properties.  So far, I've started creating the Style class as so:

      public class Style
      {
            // ...internal fields, constructors, methods, etc....

            [DisplayNameAttribute("Color"),
            CategoryAttribute("Text"),
            CssNameAttribute("color")]
            public System.Drawing.Color Color
            {
                  get { return this._color; }
                  set { this._color = value; }
            }

            [DisplayNameAttribute("Font Family"),
            TypeConverter(typeof(EnumDescriptionConverter)),
            CategoryAttribute("Text"),
            CssNameAttribute("font-family")]
            public FontFamilyStyle Font_Family
            {
                  get { return this._font_family; }
                  set { this._font_family = value; }
            }
            
            [DisplayNameAttribute("Font Size"),
            CategoryAttribute("Text"),
            CssNameAttribute("font-size")]
            public int Font_Size
            {
                  get { return this._font_size; }
                  set { this._font_size = value; }
            }

            // ... more properties...
      }

Obviously, I left out a lot of stuff, but you should be able to get the main idea.  I've created several custom attribute classes to help.  The DisplayNameAttribute class is just for specifying the name displayed in the PropertyGrid I bind to (the CategoryAttribute is an existing class also used for the PropertyGrid).  I also added a CssNameAttribute that I intended to use when parsing the object and creating the CSS file.

This way seems like it will accomplish what I need, but its just a terrible lot of work.  Does anyone have any suggestions as to a better way of doing this?  Also, any ideas for making parsing/serializing this into a CSS file easier?
LVL 9
BurntSkyAsked:
Who is Participating?
 
gregoryyoungCommented:
well I think this is a good direction to head to ...

There are some benefits and losses to this directions ... I will address the immediate ones in comparison to a attribute (name value pair collection) based implementation

strengths
strongly type = good (sometimes see below)
class structure is great to have especially if they can also parse existant documents
parsing should be much better at determining errors in a document
can build logic for targets etc into these classes (I see no reason why you couldn't say build other types of style)

weaknesses
a problem that you will run into is that different elements have different attributes and as such will require you to make many classes
different elements may require different logic same as above

I believe that the last time I looked many implementations were done as a name-value typed architecture with metadata which defined the various elements and their allowable items (thus allowing validation and a decent interface), this may be something worth looking into.

Greg
0
 
jonvaughanCommented:
You can use the PropertyCollection class.

This is the class that is used for the Extended Propreties on DataTables etc.

You could probably extend this so that it was pre-filled with a fixed number of keys on construction if you wanted to control the key value pairs in there.
0
 
BurntSkyAuthor Commented:
I suppose I could do that, but I really need the class to remain strongly typed.  If I didn't, I could just throw key-value pairs in a Hashtable and call it good.

I guess maybe a simplified class design either isn't possible or is beyond the scope of developers here.

More ideas are still welcome.
0
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
BurntSkyAuthor Commented:
I'm not sure I understand what you mean in that last sentence.  A lot of implementations I've seen use key-value pairs but aren't strongly typed.  As I said before, I really need the class to remain strongly typed because, among other reasons, I'm required to do things like binding an object to a PropertyGrid (and using TypeConverters to have drop downs with selections from enums, etc.)

Anyway, I ended up just writing up the whole class very similar to how I originally described it.  I wrote the following method to "serialize" the class into a CSS style:

      private string CreateStyleString()
      {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            PropertyDescriptorCollection pdc = this.GetProperties(new Attribute[0]);
            foreach(CustomPropertyDescriptor pd in pdc)
            {
                  // Only check the property if it has a CssNameAttribute
                  CssNameAttribute cna = pd.Attributes[typeof(CssNameAttribute)] as CssNameAttribute;
                  if(cna != null)
                  {
                        object val = pd.GetValue(this, true);
                        // Only include the property if its not still set to the value of the DefaultValue attribute
                        if(val != null && !val.Equals(pd.DefaultValue))
                              sb.Append(string.Format(" {0}: {1};", cna.CssName, val.ToString()));
                  }
            }
            return sb.ToString();
      }

It's actually a fairly intricate system, but it works.  I guess I was hoping for some sort of obvious design concept I overlooked.  Maybe it doesn't exist.
0
 
BurntSkyAuthor Commented:
It doesn't look like I'm going to get any more suggestions, plus I've already written the whole class anyway, so I'm just going to close this up and award Greg the points.
0
 
netblenderCommented:
Burnsky,

 Do you have the rest of the CSS Class that you wrote?  What did you do about pop ups in the Property Grid for pixel size or pixel percentage?

Thanks,

Netblender
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.