Flex 3 - недействительность в обработчике событий шоу нарушает жизненный цикл - PullRequest
0 голосов
/ 20 октября 2011

Просто интересно, сталкивался ли кто-нибудь с этим и исправил ли он.

Вот как воспроизвести:

Создание навигатора вкладок (или стека просмотра, и т. Д.) И добавление пары вкладок.

На вкладке добавьте обработчик события шоу. Внутри обработчика событий вызовите invalidateProperties () и invalidateDisplayList () одного из дочерних элементов вашей вкладки. Поместите точку останова в childs commitProperties () и updateDisplayList (). Вы заметите, что updateDisplayList () вызывается перед commitProperties (), что приводит к некорректному поведению.

Я заметил эту проблему, когда устанавливал поставщик данных DataGrid из обработчика шоу. Установка dataProvider приводит к тому, что сетка делает недействительными как свойства, так и displayList, сначала вызывается updateDisplayList (), а затем commitProperties (), что приводит к тому, что сетка не обновляет строки.

Похоже, корень проблемы в том, что событие show отправляется из цикла validateDisplayList () LayoutManagers, поэтому аннулирование дочернего объекта из обработчика show приводит к немедленному вызову updateDisplayList ().

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

Я рассматриваю возможность изменения UIComponent.setVisible (), который отправляет событие show, и использует callLater () для dispatchEvent (), чтобы событие show не получало отправленный цикл проверки в середине, если у кого-то нет лучшей идеи.

<mx:Script>
    <![CDATA[
        import mx.controls.Label;

        private var tabLabel:Label;
        private function onCreationComplete():void
        {
            var ifactory:IFactory = TestLabel;
            tabLabel = Label(ifactory.newInstance());
            tab1.addChild(tabLabel);
        }


        private function onTab1Show():void
        {
            tabLabel.invalidateProperties();
            tabLabel.invalidateDisplayList();
        }

    ]]>
</mx:Script>

<mx:Component id="TestLabel">
    <mx:Label text="Test">
        <mx:Script>
            <![CDATA[

                override protected function commitProperties():void
                {
                    super.commitProperties();   
                }
                override protected function updateDisplayList(w:Number, h:Number):void
                {
                    super.updateDisplayList(w, h);                  
                }

            ]]>
        </mx:Script>
    </mx:Label>
</mx:Component>

<mx:TabNavigator height="200" width="200" creationComplete="onCreationComplete()">
    <mx:Canvas id="tab1" height="100%" width="100%" label="Tab 1" show="onTab1Show()" />
    <mx:Canvas height="100%" width="100%" label="Tab 2" />
</mx:TabNavigator>

1 Ответ

0 голосов
/ 22 октября 2011

Я решил, что лучшим решением этой проблемы будет небольшая настройка LayoutManager.Он должен быть достаточно умным, чтобы при проверке объекта знать, является ли какой-либо из предыдущих этапов недействительным.

Эта проблема может проявляться несколькими способами.По сути это может привести к аннулированию объектов из методов measure () или updateDisplayList ().Например, если событие отправляется из функции measure (), а обработчик события делает недействительным размер и свойства объектов, функция measure () может быть запущена до того, как commitProperties () потенциально нарушит компонент.

Событие show отправляется из updateDisplayList () UIComponent, поэтому оно подвержено этой ошибке.

В итоге я немного изменил validateSize () и validateDisplayList ().Добавлен фрагмент кода для проверки флагов недействительности предыдущих этапов и повторной проверки объекта в случае необходимости.Также добавлен флаг, чтобы заставить LayoutManager немедленно запустить другой цикл, если объект был повторно признан недействительным из-за вышеуказанного условия.

Как и в случае с FYI, обычно не рекомендуется изменять SDK, но это может бытьсделано для каждого проекта путем копирования файла SDK в соответствующую структуру папок в вашем проекте и выполнения очистки проекта.Файл в вашем проекте будет использоваться, а не в SDK.

private function validateSize():void
{
    // trace("--- LayoutManager: validateSize --->");

    //SDK Mod - Storage for items to be re-invalidated.
    var reInvalidate:Array = [];

    var obj:ILayoutManagerClient = ILayoutManagerClient(invalidateSizeQueue.removeLargest());
    while (obj)
    {
        // trace("LayoutManager calling validateSize() on " + Object(obj));


        //SDK Mod - Check if we need to record this item due to invalid dependencies.
        if (obj is UIComponent)
        {
            if (UIComponent(obj).mx_internal::invalidatePropertiesFlag == true)
            {
                //Record the invalid item.
                reInvalidate.push(obj);
                //Set flag so LayoutManager immediately runs another cycle
                recycleImmediately = true;
            }
        }

        obj.validateSize();
        if (!obj.updateCompletePendingFlag)
        {
            updateCompleteQueue.addObject(obj, obj.nestLevel);
            obj.updateCompletePendingFlag = true;
        }

        // trace("LayoutManager validateSize: " + Object(obj) + " " + IFlexDisplayObject(obj).measuredWidth + " " + IFlexDisplayObject(obj).measuredHeight);

        obj = ILayoutManagerClient(invalidateSizeQueue.removeLargest());
    }

    //Re-invalidate any items with invalid dependencies.
    while (reInvalidate.length > 0)
        invalidateSize(ILayoutManagerClient(reInvalidate.shift()));

    if (invalidateSizeQueue.isEmpty())
    {
        // trace("Measurement Queue is empty");

        invalidateSizeFlag = false;
    }

    // trace("<--- LayoutManager: validateSize ---");
}
private function validateDisplayList():void
{

    // trace("--- LayoutManager: validateDisplayList --->");

    //SDK Mod - Storage for items to be re-invalidated.
    var reInvalidate:Array = [];

    var obj:ILayoutManagerClient = ILayoutManagerClient(invalidateDisplayListQueue.removeSmallest());
    while (obj)
    {
        // trace("LayoutManager calling validateDisplayList on " + Object(obj) + " " + DisplayObject(obj).width + " " + DisplayObject(obj).height);



        //SDK Mod - Check if we need to record this item due to invalid dependencies.
        if (obj is UIComponent)
        {
            if (UIComponent(obj).mx_internal::invalidatePropertiesFlag == true ||
                UIComponent(obj).mx_internal::invalidateSizeFlag == true)
            {
                //Record the invalid item.
                reInvalidate.push(obj);
                //Set flag so LayoutManager immediately runs another cycle
                recycleImmediately = true;
            }
        }

        obj.validateDisplayList();
        if (!obj.updateCompletePendingFlag)
        {
            updateCompleteQueue.addObject(obj, obj.nestLevel);
            obj.updateCompletePendingFlag = true;
        }

        // trace("LayoutManager return from validateDisplayList on " + Object(obj) + " " + DisplayObject(obj).width + " " + DisplayObject(obj).height);

        // Once we start, don't stop.
        obj = ILayoutManagerClient(invalidateDisplayListQueue.removeSmallest());
    }

    //Re-invalidate any items with invalid dependencies.
    while (reInvalidate.length > 0)
        invalidateDisplayList(ILayoutManagerClient(reInvalidate.shift()));

    if (invalidateDisplayListQueue.isEmpty())
    {
        // trace("Layout Queue is empty");

        invalidateDisplayListFlag = false;
    }

    // trace("<--- LayoutManager: validateDisplayList ---");
}

Затем внутри doPhasedInstantiation ().,.

if (invalidatePropertiesFlag ||
        invalidateSizeFlag ||
        invalidateDisplayListFlag)
    {
        //SDK Mod - Check if we re-invalidated any items durring the cycle. 
        if (recycleImmediately == false)
        {
            //No items were re-invalidated, default behavior.
            callLaterObject.callLater(doPhasedInstantiation);
        }
        else
        {
            //We re-invalidated items durring the current cycle, run another cycle immediately and bail out.
            recycleImmediately = false;
            doPhasedInstantiation();
            return;
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...