Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Creating a class to represent a CSS StyleSheet

Posted on 2005-04-28
6
Medium Priority
?
475 Views
Last Modified: 2010-05-18
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?
0
Comment
Question by:BurntSky
6 Comments
 
LVL 10

Expert Comment

by:jonvaughan
ID: 13915025
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
 
LVL 9

Author Comment

by:BurntSky
ID: 13919507
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
 
LVL 37

Accepted Solution

by:
gregoryyoung earned 1500 total points
ID: 13923006
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 9

Author Comment

by:BurntSky
ID: 13929503
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
 
LVL 9

Author Comment

by:BurntSky
ID: 13971259
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
 

Expert Comment

by:netblender
ID: 15121638
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

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…
Loops Section Overview

580 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question