2012-03-03 1 views
0

ли кто-нибудь, пожалуйста, есть идея, почему я получаю сообщение об ошибке выполнения:ArayList в DataProvider для списка: Индекс 0 находится вне диапазона 0

RangeError: Error #1125: The index 0 is out of range 0. 
    ........ 
    at Popup/update()[Popup.mxml:80] 
    at PopupTest/showPopup()[PopupTest.mxml:45] 
    at PopupTest/___btn_click()[PopupTest.mxml:52] 

при вызове функции:

private function showPopup(event:MouseEvent):void { 
    _popup.update(new Array('Pass' , 
     '6♠', '6♣', '6♦', '6♥', '6 x', 
     '7♠', '7♣', '7♦', '7♥', '7 x', 
     '8♠', '8♣', '8♦', '8♥', '8 x', 
     '9♠', '9♣', '9♦', '9♥', '9 x', 
     '10♠', '10♣', '10♦', '10♥', '10 x'), true, 80); 
} 

Как будто мой _list не будет иметь никаких записей на всех (? но почему я назначаю _data.source = арг) и, таким образом, _list.ensureIndexIsVisible (0) вызова потерпит неудачу в строке 80:

<?xml version="1.0" encoding="utf-8"?> 
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    width="220" height="200" 
    initialize="init(event)"> 

    <fx:Script> 
     <![CDATA[ 
      import mx.collections.ArrayList; 
      import mx.events.FlexEvent; 
      import mx.utils.ObjectUtil; 

      private static const FORCE:uint = 20; 

      [Bindable] 
      private var _data:ArrayList = new ArrayList(); 

      private var _timer:Timer = new Timer(1000, 120); 

      private function init(event:FlexEvent):void { 
       _timer.addEventListener(TimerEvent.TIMER, timerUpdated); 
       _timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleted); 
      } 

      public function close():void { 
       _timer.reset(); 
       _data.source = null; 
       visible = false; 
      } 

      private function timerUpdated(event:TimerEvent=null):void { 
       var seconds:int = _timer.repeatCount - _timer.currentCount; 
       title = 'Your turn! (' + seconds + ')'; 
       // show panel for cards too 
       if (seconds < FORCE) 
        visible = true; 
      } 

      private function timerCompleted(event:TimerEvent=null):void { 
       title = 'Your turn!'; 
       close(); 
      } 

      public function update(args:Array, bidding:Boolean, seconds:int):void { 
       if (seconds <= 0) { 
        close(); 
        return; 
       } 

       // nothing has changed 
       if (ObjectUtil.compare(_data.source, args, 0) == 0) 
        return; 
       _data.source = args; 

       if (args == null || args.length == 0) { 
        close(); 
        return; 
       } 

       if (seconds < FORCE || bidding) 
        visible = true; 

       _timer.reset(); 

       title = 'Your turn! (' + seconds + ')'; 
       _list.ensureIndexIsVisible(0); // the line 80 
       _timer.repeatCount = seconds; 
       _timer.start(); 
      } 
     ]]> 
    </fx:Script> 

    <s:VGroup paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10" gap="10" width="100%" height="100%"> 
     <s:List id="_list" dataProvider="{_data}" width="100%" height="100%" fontSize="24" itemRenderer="RedBlack" /> 
    </s:VGroup> 
</s:Panel> 

ответ

1

причина

Вы добавляете новый массив Allright, но затем начинает создавать список ItemRenderers на основе элементов, которые находятся в этом массиве. Это занимает некоторое время и происходит асинхронно. Тем временем вы говорите «show me item 1», но ItemRenderer для элемента 1 еще не существует. Это будет очень скоро, но не сейчас. Вот почему вы получаете индексную ошибку.

раствор

Вы должны быть уверены, что список будет сделано создание ItemRenderers перед вызовом этого метода. Самый простой способ решить эту ситуацию - хотя определенно не самый чистый - это просто подождать следующего цикла рендеринга, используя пресловутый callLater().

callLater(_list.ensureIndexIsVisible, [0]); 

Это по сути говоря: ждать следующего цикла рендеринга, а затем вызвать ensureIndexIsVisible() на _list с параметром 0.

(На стороне записки: если вы действительно хотите только индекс 0 Вся эта вещь довольно бессмысленно, потому что я думаю, список прокручивается назад к вершине, когда ее DataProvider изменяется в любом случае)

очиститель раствор

Вы можете прослушать список для события RendererExistenceEvent#RENDERER_ADD. Это будет отправляться всякий раз, когда в список добавляется новый ItemRenderer и он содержит ссылку на индекс элемента в списке, данных и самом ItemRenderer. Однако в вашем случае нам нужен только «индекс». Всякий раз, когда ItemRenderer добавляется индекс 0 мы будем прокручивать назад к началу:

_list.addEventListener(RendererExistenceEvent.RENDERER_ADD, onRendererAdded); 

private function onRendererAdded(event:RendererExistenceEvent):void { 
    if (event.index == 0) myList.ensureIndexIsVisible(0); 
} 

Это сразу же перейти к вершине при добавлении первого ItemRenderer и не нужно ждать, пока все они не будут готовы ,

+0

Спасибо, ** callLater (_list.ensureIndexIsVisible, [0]); ** работает, а также удаляет и считывает все: ** _ data.removeAll(); для каждого (var str: String в args) _data.addItem (str); ** Но нет ли более чистого способа * kick * List о том, что его содержимое dataProvider или dataProvider изменилось? –

+0

Не могу ли я использовать ** _ data.itemUpdated() ** здесь? –

+1

Список уже знает, что данные изменились. Вот почему он начинает добавлять ItemRenderers. Нам нужно знать, когда это делается с помощью ItemRenderers. Я посмотрю, смогу ли я найти подходящее событие для этого. – RIAstar