2010-10-18 16 views
9

Tôi có phần bảng điều khiển sau đây gọi là AdvancedPanel với controlBarContent:Làm thế nào để kế thừa các trạng thái với mxml?

<!-- AdvancedPanel.mxml --> 
<s:Panel> 
    <s:states> 
    <s:State name="normal" /> 
    <s:State name="edit" /> 
    </s:states> 
    <s:controlBarContent> 
    <s:Button 
     includeIn="edit" 
     label="Show in edit" 
     /> 
    <s:Button 
     label="Go to edit" 
     click="{currentState='edit'}" 
     /> 
    </s:controlBarContent> 
</s:Panel> 

Tôi tạo ra một bảng thứ hai, gọi là CustomAdvancedPanel dựa trên AdvancedPanel kể từ khi tôi không muốn redeclare các controlBarContent

<!-- CustomAdvancedPanel.mxml --> 
<local:AdvancedPanel> 
    <s:Button includeIn="edit" label="Extra edit button" /> 
</local:AdvancedPanel> 

này không hoạt động, vì trạng thái 'chỉnh sửa' trong CustomAdvancedPanel không được khai báo theo trình biên dịch. Tôi phải redeclare chỉnh sửa trạng thái trong CustomAdvancedPanel.mxml như sau:

<!-- CustomAdvancedPanel.mxml with edit state redeclared --> 
    <local:AdvancedPanel> 
     <local:states> 
     <s:State name="normal" /> 
     <s:State name="edit" /> 
     </local:states> 
     <s:Button includeIn="edit" label="Extra edit button" /> 
    </local:AdvancedPanel> 

Sử dụng CustomAdvancedPanel bên trong một thành phần ứng dụng cho thấy một bảng trống với nút "Go để chỉnh sửa". Nhưng khi tôi nhấp vào nó, nút "Chỉnh sửa bổ sung" sẽ hiển thị, nhưng nút "Hiển thị trong chỉnh sửa" bên trong controlBar thì không.

Khi CustomAdvancedPanel trống, không có trạng thái được khai báo lại và "Nút chỉnh sửa bổ sung", bảng điều khiển hoạt động tốt.

Tôi nghĩ rằng đó là vì đối tượng nhà nước được khai báo trong AdvancedPanel không giống như CustomAdvancedPanel, vì vậy trạng thái khác nhau, ngay cả khi chúng có cùng tên. Tuy nhiên. Tôi không thể sử dụng các trạng thái của AdvancedPanel bên trong CustomAdvancedPanel mà không cần (lại) khai báo chúng trong mxml.

Có cách nào để đạt được loại tái sử dụng không? Hoặc là có một cách tốt hơn để có được kết quả tương tự?

+0

+1 cho câu hỏi được nói rõ, với mẫu. – JeffryHouser

Trả lời

2

Tôi khuyên bạn nên sử dụng kiến ​​trúc da của Spark để đạt được mục tiêu của bạn. Bởi vì các trạng thái da được thừa hưởng trong thành phần máy chủ, bạn có thể đặt tất cả logic theo cách OOP. Nhưng da vẫn sẽ chứa mã trùng lặp :(Dù sao nó là tốt hơn so với bản sao mã của tất cả các thành phần

Vì vậy AdvancedPanel của chúng ta sẽ trông giống như sau:.

package 
{ 
    import flash.events.MouseEvent; 

    import spark.components.supportClasses.ButtonBase; 
    import spark.components.supportClasses.SkinnableComponent; 

    [SkinState("edit")] 
    [SkinState("normal")] 
    public class AdvancedPanel extends SkinnableComponent 
    { 
     [SkinPart(required="true")] 
     public var goToEditButton:ButtonBase; 
     [SkinPart(required="true")] 
     public var showInEditButton:ButtonBase; 

     private var editMode:Boolean; 

     override protected function getCurrentSkinState():String 
     { 
      return editMode ? "edit" : "normal"; 
     } 

     override protected function partAdded(partName:String, instance:Object):void 
     { 
      super.partAdded(partName, instance); 
      if (instance == goToEditButton) 
       goToEditButton.addEventListener(MouseEvent.CLICK, onGoToEditButtonClick); 
     } 

     override protected function partRemoved(partName:String, instance:Object):void 
     { 
      super.partRemoved(partName, instance); 
      if (instance == goToEditButton) 
       goToEditButton.removeEventListener(MouseEvent.CLICK, onGoToEditButtonClick); 
     } 

     private function onGoToEditButtonClick(event:MouseEvent):void 
     { 
      editMode = true; 
      invalidateSkinState(); 
     } 
    } 
} 

Và đối với CustomAdvancedPanel:

package 
{ 
    import spark.components.supportClasses.ButtonBase; 

    public class CustomAdvancedPanel extends AdvancedPanel 
    { 
     [SkinPart(required="true")] 
     public var extraEditButton:ButtonBase; 
    } 
} 

Tất nhiên bạn có thể kế thừa từ lớp Panel nhưng tôi đã làm mẫu mã đơn giản hơn.

Và da:

<?xml version="1.0" encoding="utf-8"?> 
<!-- AdvancedPanelSkin.mxml --> 
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"> 
    <fx:Metadata> 
     [HostComponent("AdvancedPanel")] 
    </fx:Metadata> 
    <s:states> 
     <s:State name="normal" /> 
     <s:State name="edit" /> 
    </s:states> 
    <s:Panel left="0" right="0" top="0" bottom="0"> 
     <s:controlBarContent> 
      <s:Button id="showInEditButton" label="Show in edit" includeIn="edit" /> 
      <s:Button id="goToEditButton" label="Go to edit" /> 
     </s:controlBarContent> 
    </s:Panel> 
</s:Skin> 

Và:

<?xml version="1.0" encoding="utf-8"?> 
<!-- CustomAdvancedPanelSkin.mxml --> 
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"> 
    <fx:Metadata>[HostComponent("CustomAdvancedPanel")]</fx:Metadata> 
    <s:states> 
     <s:State name="normal" /> 
     <s:State name="edit" /> 
    </s:states> 
    <s:Panel left="0" right="0" top="0" bottom="0"> 
     <s:Button includeIn="edit" label="Extra edit button" id="extraEditButton" /> 
     <s:controlBarContent> 
      <s:Button id="showInEditButton" label="Show in edit" includeIn="edit" /> 
      <s:Button id="goToEditButton" label="Go to edit" /> 
     </s:controlBarContent> 
    </s:Panel> 
</s:Skin> 
1

AFAIK trạng thái của thành phần không vượt qua thành phần được kế thừa. Hãy suy nghĩ về nó - nếu đó là trường hợp (nếu bạn có thể thừa hưởng các bang) thì nó sẽ làm cho cuộc sống thực sự phức tạp bất cứ khi nào bạn muốn mở rộng một thành phần; bạn sẽ phải nhận thức được tất cả các trạng thái thừa hưởng và không bước lên các ngón chân của chúng.

+1

Thêm trong CustomAdvancedPanel mà không cần redeclaring các tiểu bang trả về ba trạng thái từ AdvancedPanel (bình thường, chỉnh sửa, vô hiệu hóa) Tuy nhiên. Bạn không thể sử dụng chúng trong mxml, bởi vì trình biên dịch nói rằng chúng không có ở đó, nhưng chúng giống như datagrid gợi ý. – Treur

0

Tôi cho rằng đó là giới hạn của lập trình OO, nhưng không chắc chắn chính xác là gì. Tôi không có chuyên gia Flex nhưng tôi nghĩ về nó từ một quan điểm lập trình hướng đối tượng và đây là những gì tôi nghĩ sẽ xảy ra:

Trước tiên, khi bạn tạo một đối tượng, Flex (hoặc bất kỳ ngôn ngữ OO) nào tự động tạo bản sao của đối tượng đó VÀ một bản sao riêng của đối tượng cha của nó, do đó tạo ra một bản sao riêng của đối tượng cha của nó và như vậy trên toàn bộ cây đối tượng. Điều đó nghe có vẻ lạ nhưng như một ví dụ về điều này, khi bạn viết super() trong một hàm tạo, bạn đang gọi hàm tạo của lớp cha.

Flex có nội dung gọi là "thuộc tính". Điều này tương đương với những gì trong Java sẽ là một trường thành viên riêng (biến) với một phương thức getter và setter công khai. Khi bạn khai báo

<local:states>xyz</local:states> 

bạn đang nói một cách hiệu quả

states = xyz 

đó lần lượt là AS tương đương nói

setStates(xyz) 

Phần quan trọng, và đây là một nguyên tắc chung về tài sản, là setStates là một phương thức công khai, bất cứ ai cũng có thể gọi nó. Tuy nhiên, các mảng của chính nó là riêng tư. Nếu bạn không khai báo, CustomAdvancedPanel không có thuộc tính trạng thái. Nó không có phương thức setStates hoặc getStates. Tuy nhiên, vì setStates/getStates là public, nó thừa hưởng chúng từ AdvancedPanel nên nó funcions như thể nó có các phương thức này.Khi bạn gọi một trong những phương thức này (nhận hoặc thiết lập mảng trạng thái), nó thực sự gọi phương thức nơi nó tồn tại, nằm trong đối tượng mẹ của nó, AdvancedPanel. Khi AdvancedPanel thực thi phương thức giá trị của mảng trạng thái trong chính AdvancedPanel, được đọc hoặc thiết lập. Đây là lý do tại sao khi bạn không redeclare bất kỳ tiểu bang trong CustomAdvancedPanel tất cả mọi thứ hoạt động hoàn hảo - bạn nghĩ rằng bạn đang thiết lập và nhận được các tiểu bang mảng trong CustomAdvancedPanel nhưng trong thực tế đằng sau hậu trường bạn đang hoạt động trên các tiểu bang mảng trong đối tượng cha mẹ AdvancedPanel, đó là hoàn toàn tốt đẹp và tốt.

Bây giờ bạn xác định lại mảng trạng thái trong CustomAdvancedPanel - điều gì đang xảy ra? Hãy nhớ rằng việc khai báo một thuộc tính trong Flex giống như khai báo một biến cấp lớp riêng và các bộ định tuyến và các bộ định tuyến công khai. Vì vậy, bạn đang đưa ra CustomAdvancedPanel một mảng riêng được gọi là trạng thái và getters công cộng và setters để có được/thiết lập mảng đó. Những getters và setters sẽ ghi đè lên những cái từ AdvancedPanel. Vì vậy, bây giờ ứng dụng của bạn sẽ tương tác với CustomAdvancedPanel theo cùng một cách nhưng đằng sau hậu trường bạn không còn hoạt động trên các phương thức/biến của AdvancedPanel mà đúng hơn là trên các phương thức bạn đã khai báo trong CustomAdvancedPanel. Điều này giải thích tại sao khi bạn thay đổi trạng thái của CustomAdvancedPanel, phần được kế thừa từ AdvancedPanel không phản ứng, vì màn hình của nó được liên kết với mảng trạng thái trong AdvancedPanel, vẫn tồn tại độc lập.

Vậy tại sao không phải là includeIn được cho phép trong ví dụ cơ bản mà bạn không redeclare các tiểu bang? Tôi không biết. Hoặc đó là một lỗi, hoặc có lẽ nhiều khả năng, có một lý do chính đáng về ngôn ngữ/OO tại sao nó không bao giờ có thể làm việc.

Có thể giải thích của tôi không hoàn toàn chính xác. Đó là như xa như tôi hiểu mọi thứ. Bản thân tôi không biết tại sao điều đó thực sự xảy ra khi xem xét Nút được đề cập là một phần của siêu lớp. Một vài thử nghiệm thú vị sẽ là:

  1. chuyển trình xử lý nhấp chuột vào phương thức công khai thực tế thay vì nội tuyến.
  2. thêm super.currentState = 'edit' vào trình xử lý nhấp chuột.

Nếu bạn muốn tìm hiểu thêm về tất cả các công cụ thừa kế này, hãy viết một số lớp đơn giản trong ActionScript hoặc Flex với một lớp kế thừa khác và thực hiện các cuộc gọi hàm khác nhau để xem điều gì xảy ra.

0

"Hoặc có cách nào tốt hơn để có được kết quả tương tự không?"

Vì bạn đã hỏi và vì bạn không đưa ra trường hợp rõ ràng về nhu cầu cần thêm thành phần CustomAdvancedPanel, việc đặt "nút chỉnh sửa bổ sung" trong thành phần AdvancedPanel là giải pháp đơn giản nhất.

<!-- AdvancedPanel.mxml --> 
<s:Panel> 
    <s:states> 
    <s:State name="normal"/> 
    <s:State name="edit"/> 
    </s:states> 
    <s:Button includeIn="edit" label="Extra edit button"/> 
    <s:controlBarContent> 
    <s:Button 
     includeIn="edit" 
     label="Show in edit"/> 
    <s:Button 
     label="Go to edit" 
     click="{currentState='edit'}"/> 
    </s:controlBarContent> 
</s:Panel> 
0

Tất nhiên cách chính xác về mặt chính trị là sử dụng giao diện. Tuy nhiên, đối với những người thực sự chỉ muốn thừa kế quyền lực thừa kế trạng thái cho các lớp MXML ở đây là một công việc xung quanh mà tôi đã tìm thấy.

Để phương thức này hoạt động, lớp MXML mở rộng phải khai báo chính xác cùng trạng thái của lớp MXML cơ sở, không còn nữa và không kém, tất cả đều có tên giống nhau.

Sau đó, trong lớp học kéo dài chèn các phương pháp sau đây:

 override public function set states(value:Array):void 
     { 
      if(super.states == null || super.states.length == 0) 
      { 
       super.states = value; 

       for each (var state:State in value) 
       { 
        state.name = "_"+state.name; 
       } 
      } 
      else 
      { 
       for each (var state:State in value) 
       { 
        state.basedOn = "_"+state.name; 
        super.states.push(state); 
       } 
      } 
     } 

này hoạt động bởi vì như các thành phần được tạo ra biến quốc gia được thiết lập hai lần, một lần bởi các lớp cơ sở, và một lần bởi lớp mở rộng. Cách giải quyết này chỉ kết hợp chúng với nhau.