15 Replies Latest reply on Sep 3, 2006 11:23 PM by cristian.rotundu

    Changing the source of <mx:Style> at run time

    Matlus Level 1
      Is there a way to be able to change the stylesheet for an application at run time? Or is the only way to handle it on the server?
        • 1. Re: Changing the source of <mx:Style> at run time
          peterent Level 2
          You can change styles dynamically using the StyleManager. Check the docs on that.
          • 2. Re: Changing the source of <mx:Style> at run time
            Matlus Level 1
            Peter

            Thank you for your reply.

            The question was if I can change stylesheets at run time and not styles. I know I can change styles at run time, but I need to be able to change the whole stylesheet.

            Before I went down the route of developing my own way of changing stylesheets I wanted to make sure I didn't miss anything.
            • 3. Re: Changing the source of <mx:Style> at run time
              peterent Level 2
              You cannot swap entire stylesheets at runtime in this release.
              • 4. Re: Changing the source of <mx:Style> at run time
                CoolCountDracula Level 1
                can you please tell us a way to allow user changable themes
                • 5. Re: Changing the source of <mx:Style> at run time
                  yaroze
                  Hi. I've been dealing with stylesheet battles myself, and what I think the best way to do this is to create a custom disk loader with urlLoader and then parse in the styles and create StyleSheet objects. Then you have your own styles contained in object format.

                  What do you think?
                  • 6. Re: Changing the source of <mx:Style> at run time
                    CoolCountDracula Level 1
                    nice thinking but wud have to c it work b4 i bet it can be done. with flex u never know even the most obvious is sometimes the most impossible.

                    i was thinking something a bit simpler. maybe not css files but if we can write a custom style parser we can load it at run time and set the styles manually.
                    • 7. Re: Changing the source of <mx:Style> at run time
                      Matlus Level 1
                      Yes, I agree that the most obvious is either not possible or left to the user to implement.

                      Having read the docs, I do believe one can implement ones own runtime style setter. However, I also read in the docs that setStyle is cpu intensive and should be avoided if possible so my concern is more about performance than whether it can be done or not.

                      What I'm thinking is one can have "styles" defined in an xml format that can be loaded using the URLLoader, so it possible that that the xml "stylesheet" is generated dynamically by the server or the server can determine (based on parameters the Flex app sends it) which xml stylesheet to send it back.

                      Once the dynamic stylesheet class receives the xml it parses it out and creates instances of CSSStyleDeclaration applies them using the StyleManager.
                      • 8. Re: Changing the source of <mx:Style> at run time
                        Matlus Level 1
                        Ok, I found that if you use the StyleManager to set styles you need to apply ALL style attribute (even those that you don't want to override). In order words, let say you want to apply the cornerRadius attribute to a Panel. Typically, in your stylesheet, you'd simply define this attibute and its value and nothing else. Unfortunately, if you use the StyleManager to set a style, it wipes out any other attirbutes that global.css has applied.

                        So far I've tried this with type selectors and this is the behavior. I'm hoping that if I applied this concept to class selectors I wouldn't have to re-define each and every attribute....
                        • 9. Re: Changing the source of <mx:Style> at run time
                          Matlus Level 1
                          So what you need to do is this:

                          First "get" the style using the StyleManager.getStyleDeclaration() method.
                          if it's not null, then you can simply overwrite the style attributes you want using the setStyle() method. There is no need to "re-apply" the modified style.

                          In the case where the returned reference from getStyleDeclaration() is null, you can create an instance of a CSSStyleDeclaration and apply it using the StyleManager's setStyleDeclaration() method.

                          I think it's all quite do-able. I lot of grunt work unfortunately, but it will do.
                          • 10. Re: Changing the source of <mx:Style> at run time
                            Matlus Level 1
                            For those who might be interested, here is a class that will load a xml file (that describes styles) and applies the styles found to your application.

                            The xml file is in the format:

                            <?xml version="1.0" encoding="utf-8"?>
                            <dynamicStyles>
                            <Application selectorType="type" backgroundImage="images/background.jpg"/>
                            <ApplicationControlBar selectorType="type" highlightAlphas="0.5, 0.25"/>
                            <ToggleButtonBar selectorType="type" highlightAlphas="0.5, .25"/>
                            <viewPanel borderStyle="solid" borderThickness="1" borderColor="#efefef" backgroundColor="#d0d0d0" backgroundAlpha="0.5" color="#170505" cornerRadius="5" dropShadowEnabled="true"/>
                            <infoPanel borderStyle="solid" borderThickness="1" borderColor="#7f7e7e" backgroundColor="#ffffff" backgroundAlpha="1.0" cornerRadius="5" dropShadowEnabled="false"/>
                            <infoLabel fontSize="11" fontWeight="bold"/>
                            </dynamicStyles>

                            The AS class is the following (be sure to name the .as file that same as the class name and modify the "package" section yo include any path required by your setup.

                            package
                            {
                            import mx.styles.CSSStyleDeclaration;
                            import mx.styles.StyleManager;
                            import flash.net.URLLoader;
                            import flash.net.URLRequest;
                            import flash.events.*;
                            import flash.xml.XMLNode;
                            import flash.errors.IOError;

                            public final class RuntimeStyle
                            {
                            private var _source:String;
                            public function get source():String {
                            return _source;
                            }
                            public function set source(value:String):void {
                            if (value != _source){
                            getStylesheet(value);
                            _source = value;
                            }
                            }
                            private function getStylesheet(value:String):void {
                            var urlRequest:URLRequest = new URLRequest(value);
                            var urlLoader:URLLoader = new URLLoader();
                            urlLoader.addEventListener(Event.COMPLETE, completeHandler);
                            urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
                            urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
                            urlLoader.load(urlRequest);
                            }
                            private function completeHandler(event:Event):void {
                            var loader:URLLoader = URLLoader(event.target);
                            var xmlDoc:XML = new XML(loader.data);
                            applyStyles(xmlDoc);
                            }
                            private function ioErrorHandler(event:IOErrorEvent):void {
                            throw new IOError("Error Attempting to load RuntimeStylesheet:" + source + " Original Error: " + event.text);
                            }
                            private function securityErrorHandler(event:SecurityErrorEvent):void {
                            throw new SecurityError("Error Attempting to load RuntimeStylesheet:" + source + " Original Error: " + event.text);
                            }
                            private function applyStyles(xmlDoc:XML):void {
                            var xmlList:XMLList = xmlDoc.children();
                            for each(var node:XML in xmlList) {
                            if (node.@selectorType == "type") {
                            var cssStyle:CSSStyleDeclaration = StyleManager.getStyleDeclaration(node.name());
                            if (cssStyle != null)
                            setStyle(cssStyle, node);
                            }
                            else {
                            var cssStyleDeclaration:CSSStyleDeclaration = new CSSStyleDeclaration();
                            setStyle(cssStyleDeclaration, node);
                            StyleManager.setStyleDeclaration("." + node.name().toString(), cssStyleDeclaration, true);
                            }
                            }
                            }
                            private function setStyle(cssStyleDeclaration:CSSStyleDeclaration, node:XML):void {
                            var attributes:XMLList = node.attributes();
                            for each(var attributeNode:XML in attributes) {
                            var attributeName:String = attributeNode.name().toString();
                            if (attributeName != "selectorType") {
                            var attributeValue:String = node.attribute(attributeName).toString();
                            if (attributeValue.indexOf(",") == -1)
                            cssStyleDeclaration.setStyle(attributeName, attributeValue);
                            else
                            cssStyleDeclaration.setStyle(attributeName, attributeValue.split(","));
                            }
                            }
                            }
                            }
                            }
                            • 11. Re: Changing the source of &lt;mx:Style&gt; at run time
                              Matlus Level 1
                              A quick note on how to use the RuntimeStyle class

                              <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="absolute" initialize="onInitialize()">
                              <mx:Script>
                              <![CDATA[
                              private function onInitialize():void {
                              var runtimeStyle:RuntimeStyle = new RuntimeStyle();
                              runtimeStyle.source = "myRuntimeStyles.xml";
                              }
                              ]]>
                              </mx:Script>
                              • 12. Re: Changing the source of &lt;mx:Style&gt; at run time
                                cristian.rotundu
                                hey
                                very nice approach...however would you be so kind to show us a sample xml file that can be used? or a demo of you implementation? I'd be very grateful :)

                                Cheers!
                                • 13. Changing the source of &lt;mx:Style&gt; at run time
                                  yaroze Level 1
                                  Hi, ok -- I was able to successfully do some custom parsing so I can get the styles into a stylesheet object:

                                  The URLLoader has a method called getloader on it which retrieves the information. The main information is in the regular expression which goes through each CSS definition and then parses it out.

                                  public static function onCSSLoaded( event:Event ):void {
                                  var loader:URLLoader = URLLoader( event.target.getLoader() );
                                  var styleSheet:StyleSheet = new StyleSheet();

                                  var str:String = loader.data.toString();

                                  // pattern to get CSS definitions .test { } etc
                                  var pattern:RegExp = /.*?\{.*?\}/gisx;
                                  var result:Object = pattern.exec( str );

                                  while ( result != null ) {
                                  result = pattern.exec( str );
                                  Logger.log( Logger.DEBUG, "Pattern: " + result );

                                  try {
                                  styleSheet.parseCSS( result.toString() );
                                  } catch ( e:Error ) {
                                  // Null
                                  }
                                  }

                                  Logger.log( Logger.DEBUG, "Styles: " + styleSheet.styleNames );

                                  }

                                  The nice thing about this is that you can load in your own css file and make a stylesheet object out it.

                                  Best,

                                  Austin
                                  • 14. Re: Changing the source of &lt;mx:Style&gt; at run time
                                    Matlus Level 1
                                    Do you not see my post that shows a sample xml file?
                                    • 15. Re: Changing the source of &lt;mx:Style&gt; at run time
                                      cristian.rotundu Level 1
                                      i could swear i didn't see it..errr...sorry about that, my bad. Thanks a lot again :)
                                      Cheers!