2010-02-04 3 views
1

У меня есть XML, и у него есть опция атрибута или поле со списком, разбор которого я должен динамически создавать компоненты в своем flex.Создание компонентов Flex из XML

Viatropos дал замечательный код, но я не в состоянии выполнить это ... может кто-нибудь произвести его ... спасибо

+1

необходимо задать вопрос ... – Simon

+0

Я хочу создать компоненты, читающие XML – Kevin

ответ

10

Вы можете создавать компоненты в Flex динамически с чем-то вроде этого:

Примеры данных

<?xml version="1.0" encoding="UTF-8"?> 
<components type="array"> 
    <component type="mx.controls.ComboBox"> 
     <width>100</width> 
     <height>100</height> 
     <color isStyle="true">0xff0000</color> 
     <prompt>Im a Combo Box!</prompt> 
    </component> 
    <component type="mx.controls.Button"> 
     <width>100</width> 
     <height>100</height> 
     <color isStyle="true">0xff0000</color> 
     <label>Im a Button!</label> 
    </component> 
</components> 

Sample App:

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    creationComplete="creationCompleteHandler()"> 

    <mx:Script> 
     <![CDATA[ 

      import flash.display.DisplayObject; 
      import mx.core.UIComponent; 
      import mx.controls.ComboBox; ComboBox; 

      protected function creationCompleteHandler():void 
      { 
       var components:Array = getComponentsFromXML(xml.component); 
       var i:int = 0; 
       var n:int = components.length; 
       for (i; i < n; i++) 
       { 
        panel.addChild(components[i] as DisplayObject); 
       } 
      } 

      /** 
      * Parses an XML string, returns array of new components. 
      */ 
      public function getComponentsFromXML(components:XMLList):Array 
      { 
       var result:Array = []; 
       var child:Object; 
       var component:UIComponent; 
       var type:String; 
       var clazz:Class; 
       var i:int = 0; 
       var n:int = components.length(); 
       for (i; i < n; i++) 
       { 
        child = components[i]; 
        type = [email protected]; 
        try { 
         clazz = flash.utils.getDefinitionByName(type) as Class; 
        } catch (error:ReferenceError) { 
         traceImportError(type); 
        } 

        component = new clazz(); // dynamic 

        var properties:XMLList = child.elements(); 
        var property:XML; 
        var name:String; 
        var value:Object; 

        // for each child node 
        for each (property in properties) 
        { 
         name = property.localName(); 
         value = property.toString(); 
         // create a more generic method to convert 
         // strings to numbers and whatnot 
         // this is a regular expression matching any digit 
         // check out rubular.com 
         if (/\d+/.test(value.toString())) 
          value = Number(value); 

         if (property.attribute("isStyle") == "true") 
          component.setStyle(name, value); 
         else 
          component[name] = value; 
        } 
        result.push(component); 
       } 
       return result; 
      } 

      protected function traceImportError(type:String):void 
      { 
       trace("Please include the class '" + type + "' in the swf."); 
       var names:Array = type.split("."); 
       var last:String = names[names.length - 1]; 
       trace("import " + type + "; " + last + ";"); 
      } 

     ]]> 
    </mx:Script> 

    <!-- sample data --> 
    <mx:XML id="xml" source="components.xml" /> 

    <!-- sample container --> 
    <mx:Panel id="panel" width="100%" height="100%"/> 

</mx:Application> 

До тех пор, пока у вас есть определенная структура для вашего XML, вы можете создать XMLUtil для обработки xml в целом (получение всех свойств, например, или преобразование строк в их правильный тип) и класс ComponentManifest, который принял XML-файл и преобразовать его в компоненты.

Вам также необходимо убедиться, что все классы, определенные в XML, импортируются в swf, иначе он выкинет эту ошибку. Вы можете сделать это следующим образом:

import mx.controls.ComboBox; ComboBox;

A прямой импорт, без этого второго ComboBox не будет делать это.

Это должно помочь вам начать, заполнить его при необходимости!

Откажитесь от Rubular, чтобы пообщаться с Regular Expressions, если вы хотите иметь улучшенный/расширенный синтаксический анализ xml :).

+0

Могу ли я предоставить полный код ... Я получаю некоторую ошибку – Kevin

+0

@viatropos: Спасибо за ответ, я просто наклонился что-то новое сегодня :) –

+0

Я только что узнал что-то новое сегодня [2] :) – MysticEarth

2

Вот модифицированная версия решения @ viatropos'S:

Образец данных:

<?xml version="1.0" encoding="UTF-8"?> 
<components type="array"> 
    <component type="mx.controls::ComboBox"> 
     <width>100</width> 
     <height>100</height> 
     <color isStyle="true">"0xff0000"</location> 
     <label>"Im a Combo Box!"</label> 
    </component> 
    <component type="mx.controls::Button"> 
     <width>100</width> 
     <height>100</height> 
     <color isStyle="true">"0xff0000"</location> 
     <label>"Im a Button!"</label> 
    </component> 
</components> 

Здесь, видимо, произошла ошибка, где была использована для завершения тега.

Я также добавил кавычки вокруг всех значений строк, чтобы было легче их идентифицировать.

Sample (псевдо) Метод:createComponentsFromXML(xml.components)

public function createComponentsFromXML(components:XMLList):void 
{ 
    var child:Object; 
    var component:UIComponent; 
    var i:int = 0; 
    var n:int = components.length(); 
    for (i; i < n; i++) 
    { 
     child = components[i]; 
     var clazz:Class = flash.utils.getDefinitionByName([email protected]); 
     component = new clazz(); // dynamic 
     var property:Object; 
     var value:Object; 
     var useIntVal:Boolean; 
     var intVal:int; 
     // for each child node 
     for (property in child.children()) 
     { 
      useIntVal = false; 
      value = property.toString(); 
      if(!(value.substr(1, 2) == '"' AND value.substr(-1, value.length()) == '"')) { 
       useIntVal = true; 
       intVal = parseInt(value); 
      } 
      // button["width"] = 100; 
      if (property.attribute("isStyle") == "true") 
       if(useIntVal) { 
        component.setStyle(property.localName(), intVal); 
       } else { 
        component.setStyle(property.localName(), value); 
       } 
      else { 
       if(useIntVal) { 
        component[property.localName()] = intVal; 
       } else { 
        component[property.localName()] = value; 
       } 
      } 
     } 
    } 
} 

Я реализовал преобразование в целое убедившись, что я проверить, как предполагается, является ли свойство быть строкой или внутр.

PS: У меня сейчас нет Flex, поэтому вы можете найти несколько ошибок, которые вам нужно исправить.

В этом случае вы можете захотеть иметь свой XML, как это:

<?xml version="1.0" encoding="UTF-8"?> 
<components type="array"> 
    <component type="mx.controls::ComboBox"> 
     <properties> 
      <width>100</width> 
      <height>100</height> 
      <color isStyle="true">"0xff0000"</location> 
      <label>"Im a Combo Box!"</label> 
     </properties> 
    </component> 
    <component type="mx.controls::Button"> 
     <properties> 
      <width>100</width> 
      <height>100</height> 
      <color isStyle="true">"0xff0000"</location> 
      <label>"Im a Button!"</label> 
     </properties> 
     <children> 
      <!--other children here--> 
     </children> 
    </component> 
</components> 

Потому что я сомневаюсь, что вы можете сделать с одним уровнем вложенности в гармошку.

Я оставлю реализацию функции для вас.

+0

Спасибо ... он дал ошибки ... пусть я его выработаю. – Kevin

+0

@ theband: Не стесняйтесь размещать ошибки. –

+0

Можем ли мы создавать компоненты внутри Accordian ... в зависимости от XML – Kevin