Aide - Recherche - Membres - Calendrier
Version complète : Garder le scroll sur un Datagrid
Centre de Formation Flash - Forums Adobe Flash > Rich media et intégration > Flex
ArAgorrn
Explication :

Actuellement quand on scroll sur un datagrid vers les éléments du bas, si les données qui sont dans le datagrid changent, le datagrid se replace en haut.

Illustration par ce code :
CODE
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
<mx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;
        
        private var nIndex:Number = 0;
        
        [Bindable]
        public var aCollec:ArrayCollection = new ArrayCollection();
        
        private function addItem():void
        {
            var pobj:Object = new Object();
            pobj.Field1 = nIndex;
            pobj.Field2 = nIndex+1;
            pobj.Field3 = nIndex+3;
            nIndex++;
            aCollec.addItem(pobj);
        }
        
        private function setAllData():void{
            var aCollec2:ArrayCollection = new ArrayCollection();
            //var nPos:Number = myDG.verticalScrollPosition;
            for(var i:uint = 0; i<15; i++){
                var pobj:Object = new Object();
                pobj.Field1 = i;
                pobj.Field2 = i+1;
                pobj.Field3 = i+3;
                aCollec2.addItem(pobj);
            }
            aCollec = aCollec2;
            //myDG.verticalScrollPosition = nPos;
        }
    ]]>
</mx:Script>
    <mx:Panel width="100%" layout="vertical" title="Main Panel">
        <mx:Panel width="100%" height="100%" title="Panel">
            <mx:DataGrid id="myDG" dataProvider="{aCollec}" sortableColumns="false" textAlign="center" allowMultipleSelection="true" editable="false">
                <mx:columns>
                    <mx:DataGridColumn headerText="Field1" dataField="Field1"/>
                    <mx:DataGridColumn headerText="Field2" dataField="Field2"/>
                    <mx:DataGridColumn headerText="Field3" dataField="Field3"/>
                </mx:columns>
            </mx:DataGrid>
        </mx:Panel>
        <mx:Button label="Add" click="addItem()"/>
        <mx:Button label="Change" click="setAllData()"/>
    </mx:Panel>
    
</mx:Application>


Je voudrais trouver une solution pour que le scrolling se remette à la même position après la mise à jour des données.
Comme l'exemple le montre, j'ai essayé avec verticalScrollPosition mais le datagrid a alors un comportement étrange.
ArAgorrn
Je vais m'auto-répondre juste pour apporter une précision. J'ai essayé avec scrollToIndex sans succès.

voici un code d'exemple qui montre le défaut dans l'affichage. Quand on clique sur "Fill" le DataGrid se remplit quand on clique sur "Change" il est sensé changer les données du DataGrid et se placer sur l'objet d'index 7. Le scroll bouge bien mais les éléments qui sont affichés sont les éléments 0 à 5 et tout ce qui est au-dessus est vide (essayer de scroller à la main ensuite pour voir).

Je continue mes recherches ...

CODE
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" xmlns:local="*" creationComplete="init()">
<mx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;
        
        private var nIndex:Number = 0;
        
        [Bindable]
        public var aCollec:ArrayCollection = new ArrayCollection();
        
        private function init():void{
            myDG.columns = columns;
        }
        
        private function addItems():void
        {
            for(var i:uint = 0; i<15; i++){
                var pobj:Object = new Object();
                pobj.Field1 = nIndex;
                pobj.Field2 = nIndex+1;
                pobj.Field3 = nIndex+3;
                nIndex++;
                aCollec.addItem(pobj);
            }
            aCollec.refresh();
        }
        
        private function setAllData():void{
            var aCollec2:ArrayCollection = new ArrayCollection();
            //var nPos:Number = myDG.verticalScrollPosition;
            //var nPos:Number = myDG.getScrollPos();
            for(var i:uint = 0; i<15; i++){
                var pobj:Object = new Object();
                pobj.Field1 = i;
                pobj.Field2 = i+1;
                pobj.Field3 = i+3;
                aCollec2.addItem(pobj);
            }
            aCollec = aCollec2;
            //aCollec.refresh();
            myDG.scrollToIndex(7);
            //myDG.verticalScrollPosition = nPos;
        }
    ]]>
</mx:Script>
<mx:Array id="columns">
    <mx:DataGridColumn headerText="Field1" dataField="Field1"/>
    <mx:DataGridColumn headerText="Field2" dataField="Field2"/>
    <mx:DataGridColumn headerText="Field3" dataField="Field3"/>
</mx:Array>
    <mx:Panel width="100%" layout="vertical" title="Main Panel">
        <mx:Panel width="100%" height="100%" title="Panel">
            <mx:DataGrid id="myDG" dataProvider="{aCollec}" sortableColumns="false" textAlign="center" allowMultipleSelection="true" editable="false">
            </mx:DataGrid>
        </mx:Panel>
        <mx:Button label="Fill" click="addItems()"/>
        <mx:Button label="Change" click="setAllData()"/>
    </mx:Panel>
    
</mx:Application>
ArAgorrn
Finalement j'ai trouvé la solution. Si quelqu'un en a une plus simple je reste preneur.
La voici :

CODE
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" xmlns:local="*" creationComplete="init()">
<mx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;
        
        private var nIndex:Number = 0;
        
        [Bindable]
        public var aCollec:ArrayCollection = new ArrayCollection();
        
        private function init():void{
            myDG.columns = columns;
        }
        
        private function addItems():void
        {
            for(var i:uint = 0; i<15; i++){
                var pobj:Object = new Object();
                pobj.Field1 = nIndex;
                pobj.Field2 = nIndex+1;
                pobj.Field3 = nIndex+3;
                nIndex++;
                aCollec.addItem(pobj);
            }
            aCollec.refresh();
        }
        
        private function setAllData():void{
            var aCollec2:ArrayCollection = new ArrayCollection();
            //var nPos:Number = myDG.verticalScrollPosition;
            nIndex = myDG.getScrollPos();
            for(var i:uint = 0; i<15; i++){
                var pobj:Object = new Object();
                pobj.Field1 = i;
                pobj.Field2 = i+1;
                pobj.Field3 = i+3;
                aCollec2.addItem(pobj);
            }
            aCollec = aCollec2;
            //aCollec.refresh();
            
            //myDG.verticalScrollPosition = nPos;
        }
        
        private function updateHandler():void{
            myDG.scrollToIndex(nIndex);
        }
    ]]>
</mx:Script>
<mx:Array id="columns">
    <mx:DataGridColumn headerText="Field1" dataField="Field1"/>
    <mx:DataGridColumn headerText="Field2" dataField="Field2"/>
    <mx:DataGridColumn headerText="Field3" dataField="Field3"/>
</mx:Array>
    <mx:Panel width="100%" layout="vertical" title="Main Panel">
        <mx:Panel width="100%" height="100%" title="Panel">
            <local:MyDataGrid updateComplete="updateHandler()" id="myDG" dataProvider="{aCollec}" sortableColumns="false" textAlign="center" allowMultipleSelection="true" editable="false"/>
        </mx:Panel>
        <mx:Button label="Fill" click="addItems()"/>
        <mx:Button label="Change" click="setAllData()"/>
    </mx:Panel>
    
</mx:Application>


Je suis obligé de créer un objet qui hérite de DataGrid pour accéder à la fonction scrollPositionToIndex qui est protected dans ListBase donc inaccessible.

Voici donc le code de la classe MyDataGrid :

CODE
<?xml version="1.0" encoding="utf-8"?>
<mx:DataGrid xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script>
        <![CDATA[
            public function getScrollPos():int
            {
                return scrollPositionToIndex(horizontalScrollPosition,verticalScrollPosition);
            }
        ]]>
    </mx:Script>
</mx:DataGrid>


Voilà. Si ça peut aider des gens ...

ArA
ArAgorrn
A force de parler tout seul et de faire les questions et les réponses, je vais passer pour un dingue. En tous cas voilà une version plus simple sans faire de classe qui dérive de datagrid et qui marche mieux.

CODE
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" xmlns:local="*" creationComplete="init()">
<mx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;
        
        private var nIndex:Number = 0;
        
        private var nPos:Number = 0;
        
        private var bNeedRefresh:Boolean = false;
        
        [Bindable]
        public var aCollec:ArrayCollection = new ArrayCollection();
        
        private function init():void{
            myDG.columns = columns;
        }
        
        private function addItems():void
        {
            for(var i:uint = 0; i<15; i++){
                var pobj:Object = new Object();
                pobj.Field1 = nIndex;
                pobj.Field2 = nIndex+1;
                pobj.Field3 = nIndex+3;
                nIndex++;
                aCollec.addItem(pobj);
            }
            aCollec.refresh();
        }
        
        private function setAllData():void{
            var aCollec2:ArrayCollection = new ArrayCollection();
            nPos = myDG.verticalScrollPosition;
            for(var i:uint = 0; i<15; i++){
                var pobj:Object = new Object();
                pobj.Field1 = i;
                pobj.Field2 = i+1;
                pobj.Field3 = i+3;
                aCollec2.addItem(pobj);
            }
            bNeedRefresh = true;
            aCollec = aCollec2;
        }
        
        private function updateHandler():void{
            if(bNeedRefresh){
                myDG.verticalScrollPosition = nPos;
            }
            bNeedRefresh = false;
            
        }
    ]]>
</mx:Script>
<mx:Array id="columns">
    <mx:DataGridColumn headerText="Field1" dataField="Field1"/>
    <mx:DataGridColumn headerText="Field2" dataField="Field2"/>
    <mx:DataGridColumn headerText="Field3" dataField="Field3"/>
</mx:Array>
    <mx:Panel width="100%" layout="vertical" title="Main Panel">
        <mx:Panel width="100%" height="100%" title="Panel">
            <mx:DataGrid updateComplete="updateHandler()" id="myDG" dataProvider="{aCollec}" sortableColumns="false" textAlign="center" allowMultipleSelection="true" editable="false"/>
        </mx:Panel>
        <mx:Button label="Fill" click="addItems()"/>
        <mx:Button label="Change" click="setAllData()"/>
    </mx:Panel>
    
</mx:Application>


Sur ce...

Bonne journée.
ArAgorrn
Cette fois c'est la dernière promis.

Voici une solution plus élégante et plus complète donnée sur un autre forum. J'espère qu'il ne m'en voudra pas de publier sa réponse ici...
CITATION
Bonjour,

Oui, il y a plus simple...
Pour les "vieux papy" ayant connu Flash pour faire des RIA, c'était un
problème
connu sur la méthode vPosition du Datagrid qu'il fallait résoudre avec
doLater.

En Flex, ça s'appelle verticalScrollPosition et le problème persiste
qu'il faut résoudre avec
un callLater.

Pour sélectionner un index du DataGrid, on emploie:
callLater(selectMyIndex, [myIndex]);
avec
private function selectMyIndex(newIndex:Number):void
{
myDG.selectedIndex = newIndex;
myDG.verticalScrollPosition = newIndex;
myDG.dispatchEvent(new Event("change"));
}

Mais, le probème est plus complexe pour ton cas. Car, il faut tenir
compte des tris en cours
et de la possibilité de multi-sélection du DataGrid.
Mais, pour ton cas ultra-simple, voici la solution :

CODE
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="horizontal" xmlns:local="*" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;

private var nIndex:Number = 0;

[Bindable]
public var aCollec:ArrayCollection = new ArrayCollection();

private function init():void{
myDG.columns = columns;
}

private function addItems():void
{
for(var i:uint = 0; i<15; i++){
var pobj:Object = new Object();
pobj.Field1 = nIndex;
pobj.Field2 = nIndex+1;
pobj.Field3 = nIndex+3;
nIndex++;
aCollec.addItem(pobj);
}
aCollec.refresh();
}

private function setAllData():void{
var aCollec2:ArrayCollection = new ArrayCollection();
nIndex = myDG.selectedIndex;
for(var i:uint = 0; i<15; i++){
var pobj:Object = new Object();
pobj.Field1 = i;
pobj.Field2 = i+1;
pobj.Field3 = i+3;
aCollec2.addItem(pobj);
}
aCollec = aCollec2;
callLater(selectMyIndex, [nIndex]);
}

private function selectMyIndex(newIndex:Number):void
{
myDG.selectedIndex = newIndex;
myDG.verticalScrollPosition = newIndex;
myDG.dispatchEvent(new Event("change"));
}
]]>
</mx:Script>
<mx:Array id="columns">
<mx:DataGridColumn headerText="Field1" dataField="Field1"/>
<mx:DataGridColumn headerText="Field2" dataField="Field2"/>
<mx:DataGridColumn headerText="Field3" dataField="Field3"/>
</mx:Array>

<mx:Panel width="100%" layout="vertical" title="Main Panel">
<mx:Panel width="100%" height="100%" title="Panel">
<mx:DataGrid id="myDG" dataProvider="{aCollec}"
sortableColumns="false" textAlign="center"
allowMultipleSelection="false" editable="false" />

</mx:Panel>
<mx:Button label="Fill" click="addItems()"/>
<mx:Button label="Change" click="setAllData()"/>
</mx:Panel>
</mx:Application>



CITATION


ArA
jmlm
excellente solution Merci.
Ceci est une version "bas débit" de notre forum. Pour voir la version complète avec plus d'informations, la mise en page et les images, veuillez cliquer ici.
Invision Power Board © 2001-2008 Invision Power Services, Inc.