28 Replies Latest reply on Oct 20, 2007 12:46 AM by PitySOFT

    Datagrid scroll bug??

    HITdrumHARD Level 1
      Hey all,

      I have a data grid with a numeric sort applied to one of the fields. When initially loaded from the webservice, everything appears in order. However, when you scroll to the rows below the fold, all hell breaks loose and with each scroll, the order seems to be pseudo-randomized.

      I made a quicktime to demonstrate:

      Scroll Bug Video

      Is this a horrible bug or am I doing something weird? Do I need to reapply the sort after every scroll event? (IS there a scroll event??)

        • 1. Re: Datagrid scroll bug??
          HITdrumHARD Level 1
          UPDATE:

          Applying the sort filter again on a Scroll event..... had no effect.
          • 2. Re: Datagrid scroll bug??
            ntsiii Level 3
            You are using custom ItemRenderers. Do they all use override set data() function to draw themselves?
            Tracy
            • 3. Re: Datagrid scroll bug??
              HITdrumHARD Level 1
              Its an inline itemRender. One of the components is Custom UIComponent class, using a swf symbol embed (the updown arrows). There are events on that as of now but no other functionality at this time.

              Here is the Code for the DataGrid and its renderer:

              <mx:DataGrid dataProvider="{lectureData}" width="100%" height="100%" id="Learn2Lectures" themeColor="haloGreen" scroll="scrollHandler(event)">
              <mx:columns>
              <mx:DataGridColumn id="Profs" headerText="Learn2 Lectures">
              <mx:itemRenderer>
              <mx:Component id="LectureItem">
              <mx:HBox xmlns:Asset="assets.*" creationComplete="init()" width="100%" height="25" paddingLeft="5" paddingRight="5" verticalAlign="middle" horizontalAlign="left">
              <mx:Style>
              .CourseLinkButton
              {
              font-size: 10px;
              font-family:Verdana;
              font-weight:normal;
              color:#335533;
              text-decoration:underline;
              text-roll-over-color:#003300;
              roll-over-color:#CCCCCC;
              selectionColor:#AAAAAA;
              }
              .TextInputEditTrue
              {
              font-size: 9px;
              font-family:Verdana;
              font-weight:normal;
              color:#333333;
              }
              .TextInputEditFalse
              {
              font-size: 9px;
              font-family:Verdana;
              font-weight:normal;
              color:#999999;
              }
              </mx:Style>
              <mx:Script>
              <![CDATA[
              import mx.collections.ArrayCollection;
              import Events.UpdateL2LectureEvent;
              import dataHolders.Lecture;
              private var ImVisible:Boolean;
              [Bindable]
              private var totalItems:uint;
              private var _componentsTotal:uint = 6;
              private var _componentCount:uint = 0;
              private function init():void
              {
              //set professor
              /*
              trace("****************************");
              trace("* Setting Selected Professor");
              trace("* speaker_id: " +data.speaker_id);
              //trace("* Data.parent: " +data.parent);
              trace("****************************");
              */

              moveArrows.TotalItems = outerDocument.lectureData.length;

              outerDocument.addEventListener("refreshLectures", resetProfHandler);
              totalItems = outerDocument.lectureData.length;

              }
              private function buildCounter(event:Event):void
              {
              if(_componentCount == _componentsTotal)
              {
              if(data != null)
              {
              resetProf();
              if(data.visible)
              {
              ImVisible = true;
              visButton.label = "Hide";
              visButton.selected = false;
              }
              else
              {
              ImVisible = false;
              visButton.label = "Show";
              visButton.selected = true;
              }
              inpTitle.text = data.title;
              order.text = data.eventOrder;

              inpTitle.styleName = 'TextInputEditFalse';
              LB.addEventListener(MouseEvent.CLICK,edit);
              }
              }
              else
              {
              //trace("Created "+event.currentTarget+" and it was built "+_componentCount);
              _componentCount++
              }
              }

              private function visibleHandler(event:MouseEvent):void
              {
              if(ImVisible)
              {
              ImVisible = false;
              visButton.label = "Show";
              visButton.selected = true;
              }
              else
              {
              ImVisible = true;
              visButton.label = "Hide";
              visButton.selected = false;
              }
              }
              private function edit(event:MouseEvent):void
              {
              //set test fields to editable
              inpTitle.editable = true;
              inpTitle.styleName = 'TextInputEditTrue';
              selectProfessor.enabled = true;
              visButton.enabled = true;
              moveArrows.enabled = true;
              //set click handler to save
              LB.removeEventListener(MouseEvent.CLICK,edit);
              LB.addEventListener(MouseEvent.CLICK,save);
              //set label to 'save'
              LB.label = "save";
              }
              private function save(event:MouseEvent):void
              {
              trace("SAVING!");
              //fire off save event
              var lect:Lecture = new Lecture();
              lect.course_id = data.course_id;
              lect.mediasite_id = data.mediasite_id
              lect.speaker_id = selectProfessor.selectedItem.mediasite_id;
              lect.title = inpTitle.text;
              lect.eventOrder = data.eventOrder;
              if(visButton.selected)
              {
              trace("VISIBLE BUTTON SELECTED: "+visButton.selected);
              lect.visible = false;
              }
              else
              {
              trace("VISIBLE BUTTON SELECTED: "+visButton.selected);
              lect.visible = true;
              }
              dispatchEvent(new UpdateL2LectureEvent(lect, Lectures.UPDATE_LECTURE,true));
              //set text inputs to disabled
              inpTitle.editable = false;
              inpTitle.styleName = 'TextInputEditFalse';
              selectProfessor.enabled = false;
              visButton.enabled = false;
              moveArrows.enabled = false;
              //set click handler to 'edit'
              LB.removeEventListener(MouseEvent.CLICK,save);
              LB.addEventListener(MouseEvent.CLICK,edit);
              LB.label = "edit";
              }
              private function resetProfHandler(event:Event):void
              {
              trace("Recieved Refresh Event!");
              resetProf();
              }
              private function resetProf():void
              {
              trace("Reseting Profs!");
              for(var i:uint = 0;i<outerDocument.profData.length;i++)
              {
              //trace("checking for match of: " + data.profData.getItemAt(i).mediasite_id);
              if(outerDocument.profData.getItemAt(i).mediasite_id == data.speaker_id)
              {
              //trace("got match!");
              selectProfessor.selectedIndex = i;
              break;
              }
              }
              }
              ]]>
              </mx:Script>
              <mx:CheckBox id="chk" creationComplete="buildCounter(event)" label="" width="20" height="25" paddingLeft="5" labelPlacement="left"/>
              <mx:TextInput id="inpTitle" creationComplete="buildCounter(event)" editable="false" width="100%" height="20"/>
              <mx:ComboBox id="selectProfessor" creationComplete="buildCounter(event)" dataProvider="{outerDocument.profData}" enabled="false" labelField="fullname" width="150"></mx:ComboBox>
              <mx:Button id="visButton" creationComplete="buildCounter(event)" toggle="true" height="20" fontSize="9" enabled="false" click="visibleHandler(event)" width="50"/>
              <Asset:Move_Arrows_UI id="moveArrows" creationComplete="buildCounter(event)" Position="{data.eventOrder}" TotalItems="{totalItems}" enabled="false" width="30" height="24"/>
              <mx:Label id="order" creationComplete="buildCounter(event)"/>
              <mx:LinkButton id="LB" creationComplete="buildCounter(event)" label="edit" width="45" styleName="CourseLinkButton"/>
              </mx:HBox>
              </mx:Component>
              </mx:itemRenderer>
              </mx:DataGridColumn>
              </mx:columns>
              </mx:DataGrid>
              • 4. Re: Datagrid scroll bug??
                HITdrumHARD Level 1
                short answer to your question, no I believe I am not overriding data()
                • 5. Re: Datagrid scroll bug??
                  ntsiii Level 3
                  Ugh, that is an awful lot to try to do in an inline renderer. That needs to be a component.

                  Where are the numerical values you showed in your demo movie being displayed?

                  And what does buildCounter do?

                  Tracy
                  • 6. Re: Datagrid scroll bug??
                    ntsiii Level 3
                    And what is _componentCount counting.
                    • 7. Re: Datagrid scroll bug??
                      ntsiii Level 3
                      You need to understand that ItemRenderers get recycled when you scroll, or whn the dataProvider changes. So any display in the renderer must come from the current dataProvider item. You cannot "keep" an values in a renderer. If that is what you are doing.

                      Using a separate component will help with this. All display must be invoked from the override set data() function, using the data item passed in. If the renderer extends IListItemRenderer, then you can access the listData, which give you some more flexibility.
                      Tracy
                      • 8. Re: Datagrid scroll bug??
                        HITdrumHARD Level 1
                        It was originally a seperate component, to be used as an itemRenderer that way, but i couldn't figure out a solution for 'outerDocument' which seems only to work if your renderer is inline. Are you talking a component for the itemRenderer, or for the datagrid itself?

                        And why would the data in the render be recycled on scroll? That seems like a bug to me. How is one supposed to view the data at all if it gets lost when you scroll to see it?

                        Anyway, thanks for your help. I am still not sure what to do about outerDocument, if I recreate the renderer as a seperate component again...
                        • 9. Re: Datagrid scroll bug??
                          ntsiii Level 3
                          A component for the itemRenderer.

                          All of the list-based components only instantiate enough item renderers to display what is visible. It is like a "window" on the data. When you scroll, each of the item renderers re-renders itself with the new row data. So the renderer is re-used, not the data.

                          You can access stuff outside of the renderer using application.application. Also, if you implement IListItemRenderer, you can access listData, which is the entire dataProvider.

                          Tracy
                          • 10. Re: Datagrid scroll bug??
                            HITdrumHARD Level 1
                            Thanks for that! I will give it a try.
                            • 11. Re: Datagrid scroll bug??
                              HITdrumHARD Level 1
                              I don't think application.application is what I am looking for.

                              outerDocument only refers to the component that the DataGrid lives on that my ItemRenderer is being used by. application.application seems to reach all the way out the the HTML file that the entire SWF lives on.

                              What I need is a way to access an ArrayCollection on the component that contains the DataGrid. outerDocument will do that, but only if the ItemRenderer is 'inline' using <mx:Component> as it's wrapper. Is there a better pattern for this? I am sure I am simply painting myself into a corner with the way I've put everything together.
                              • 12. Re: Datagrid scroll bug??
                                HITdrumHARD Level 1
                                The numerical values are the intended display order. A sort is done on the dataProvider before rendering. As you can see in the movie, the order is not maintained due to the 'recycling' you mentioned while scrolling.
                                • 13. Re: Datagrid scroll bug??
                                  ntsiii Level 3
                                  Let's back up. What do you need from outside the renderer?
                                  • 14. Re: Datagrid scroll bug??
                                    HITdrumHARD Level 1
                                    I need to access a different dataProvider to fill the combobox than the dataProvider used within the rest of the controls in my renderer. I figured (perhaps wrongly?) that it would be more efficient to bind directly to it rather than combine the two data sources into a 3rd for my renderer to use.
                                    • 15. Re: Datagrid scroll bug??
                                      ntsiii Level 3
                                      So the combobox dataprovider is the same for all rows, then, correct?

                                      If so then your goal seems to be reasonable. However, if you have control of the back end, and we are not talking about a huge amount of data, then duplicating the combobox options in every item is the quickest solution. I really need to do some testing with using external data with itemRenderers before i can say how well it works and how to do it. ItemRenderers are really oriented around the item data.

                                      If you want to keep banging on it, try referencing the external dataProvider with parent, parentDocument, or Application.application.

                                      Tracy
                                      • 16. Datagrid scroll bug??
                                        esterojas Level 1
                                        hello, I think I am having an issue that is related to this, but am not sure. I have a tilelist that uses an itemrenderer component which contains an image. The component then uses the data.someid to set the image source on the complete event of the component. The tilelist is also drag enabled so i can drag items to another spot. Everything works great... except when I scroll up and or down very quickly, the image shown ends up different than the one dragged. If I scroll slow or at a normal speed everything works great. Also, after I scroll quickly and I know the items showing are "wrong" I can scroll slowly until it is out of the visible range and then scroll back to where I can see it, and the correct image shows. It looks like it is:

                                        - cached somehow
                                        - starts rendering an item and never gets a chance to catch up, so it end up displaying the wrong image
                                        - or the data in the renderer gets out of sync with the parent

                                        anyone have any ideas on what I could try? I have been researching this problem and learing about renderers for over a day, but no luck. Any help would be outstanding!

                                        Thanks!!!

                                        • 17. Re: Datagrid scroll bug??
                                          ntsiii Level 3
                                          Read the third post in this thread. Do they?
                                          Tracy
                                          • 18. Re: Datagrid scroll bug??
                                            esterojas Level 1
                                            Thanks for your quick reply! No, I don't think I am doing that. Here is the main part of my code that sets the image inside the renderer:

                                            complete() fires on the creationComplete event in the renderer.

                                            private function complete():void {

                                            try{
                                            if (data.AssetID + "" != "" || data.AssetID != null)
                                            {
                                            ThumbImage.source = URLVar + "/Image.aspx?assetid=" + data.AssetID+ "&w=50&h=60";
                                            ThumbImage.toolTip = data.AssetName;
                                            }
                                            else
                                            {
                                            ThumbImage.source = "images/MiXX_DragHere.png";
                                            }
                                            }
                                            catch(err:Error) {}

                                            And the ThumbImage is just:
                                            <mx:Image id="ThumbImage" />

                                            Does that help? There are about 200 images rendered in one tilelist with 3-4 columns. I can send you a link to the alpha version of the site so you can see the problem in action if you think that might help. I have been struggling with this for a while now. Any help would be great. Thanks again!
                                            • 19. Re: Datagrid scroll bug??
                                              ntsiii Level 3
                                              That will NOT work.

                                              ItemRenderers are recycled when the underlying data changes or when you scroll. A renderer is just a window to the data. When you scroll a line into view, all of the renderers are re-rendererd, they each get a new dataProvider item, and they reset their states based on data in the new item.

                                              creationComplete only fires when the component is created. Since the renderers are re-used, this event does not fire when you scroll.

                                              What you are doing in creationComplete should be done in an :
                                              public overrides set data(o:Object):void
                                              function.

                                              Read up on itemRenderers some. I have some simple examples on CFLEX.net

                                              Tracy
                                              • 20. Re: Datagrid scroll bug??
                                                esterojas Level 1
                                                Thanks for your help!! That is just the kind of advice I was looking for. I will let you know how it goes.
                                                Have a great one!
                                                • 21. Datagrid scroll bug??
                                                  esterojas Level 1
                                                  Again...Very helpful! Quick question though, I found a quick example at:
                                                  http://livedocs.adobe.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=Live Docs_Book_Parts&file=cellrenderer_072_30.html
                                                  I used this exact code just to test, but as a renderer for a tilelist. It seems that at the time the data is set, it doesn't know that the onSale image object exists, so it gives an error when trying to set the source. Any insight on that?

                                                  Thanks again!!
                                                  • 22. Re: Datagrid scroll bug??
                                                    ntsiii Level 3
                                                    That should not happen, I do not see why it would.

                                                    So it is giving a run-time error?
                                                    Tracy
                                                    • 23. Datagrid scroll bug??
                                                      esterojas Level 1
                                                      Yeah, it is strange... here is a link to basic example:
                                                      http://www.kickplay.com/Mixx/test.html

                                                      You can see the error it produces is below. I have traced it and it occurs when I try to set a property of the image (or label). It says the image is null at that point. I do a check to if not null... works then but nothing really show, but it looks like the space for the item is there since there is a scrollbar still that looks like the correct "hight" for what should be there. Hope this helps...

                                                      TypeError: Error #1009: Cannot access a property or method of a null object reference.
                                                      at Components::testRenderer/set data()
                                                      at mx.controls.listClasses::TileBase/mx.controls.listClasses:TileBase::makeRowsAndColumns()
                                                      at mx.controls.listClasses::ListBase/mx.controls.listClasses:ListBase::updateDisplayList()
                                                      at mx.controls.listClasses::TileBase/mx.controls.listClasses:TileBase::updateDisplayList()
                                                      at mx.core::UIComponent/validateDisplayList()
                                                      at mx.managers::LayoutManager/::validateDisplayList()
                                                      at mx.managers::LayoutManager/::doPhasedInstantiation()
                                                      at Function/ http://adobe.com/AS3/2006/builtin::apply()
                                                      at mx.core::UIComponent/::callLaterDispatcher2()
                                                      at mx.core::UIComponent/::callLaterDispatcher()

                                                      I combined two adobe examples to test. The code for the renderer is exactly the same execpt I changed the image to use the one that comes from the data provider. The main code for in the application that contains the tilelist is:

                                                      <?xml version="1.0" encoding="utf-8"?>
                                                      <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="absolute">
                                                      <mx:Script>
                                                      <![CDATA[

                                                      [Bindable]
                                                      [Embed(source="images/MiXX_DragHere.png")]
                                                      public var phone1:Class;

                                                      ]]>
                                                      </mx:Script>

                                                      <mx:TileList id="CameraSelection" height="250" width="300"
                                                      maxColumns="2" rowHeight="225" columnWidth="125" itemRenderer="Components.testRenderer">
                                                      <mx:dataProvider>
                                                      <mx:Array>
                                                      <mx:Object label="Nokia 6630" icon="{phone1}"/>
                                                      <mx:Object label="Nokia 6680" icon="{phone1}"/>
                                                      <mx:Object label="Nokia 7610" icon="{phone1}"/>
                                                      <mx:Object label="Nokia LGV" icon="{phone1}"/>
                                                      <mx:Object label="Nokia LMV" icon="{phone1}"/>
                                                      </mx:Array>
                                                      </mx:dataProvider>
                                                      </mx:TileList>
                                                      </mx:Application>

                                                      In my real app, I use web services etc to retieve the data, but I was trying to issolate the issue and it still has the same one with this base case. Again any help would be fantastic!

                                                      Thanks again for all your responses!
                                                      • 24. Re: Datagrid scroll bug??
                                                        ntsiii Level 3
                                                        Post the full code for testRenderer, With this sample test app, I will run it to see if I can see anything.
                                                        • 25. Re: Datagrid scroll bug??
                                                          esterojas Level 1
                                                          Hey there here is the full code for the test itemRenderer:

                                                          <?xml version="1.0"?>
                                                          <!-- itemRenderers\component\myComponents\RendererDGImageSelect.mxml -->
                                                          <mx:HBox xmlns:mx=" http://www.adobe.com/2006/mxml"
                                                          horizontalAlign="center">

                                                          <mx:Script>
                                                          <![CDATA[

                                                          import mx.events.FlexEvent;

                                                          override public function set data(value:Object):void {
                                                          if(value != null) {
                                                          super.data = value;
                                                          onSale.source = value.icon;
                                                          testLabel.text = value.label;
                                                          }
                                                          // Dispatch the dataChange event.
                                                          dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
                                                          }
                                                          ]]>
                                                          </mx:Script>

                                                          Thanks once again!

                                                          <mx:Image id="onSale" height="20"/>
                                                          <mx:Label id="testLabel"></mx:Label>
                                                          </mx:HBox>
                                                          • 26. Re: Datagrid scroll bug??
                                                            ntsiii Level 3
                                                            Ok, I am surprised that the data property is being set before the component is initialized, but here is the fix. basically, we do not set the subcomponent properties right away, but defer them until the next render event, using invalidateProperties, and overriding that function.
                                                            Tracy
                                                            (I wish the forum did not destroy code formatting!)

                                                            <?xml version="1.0"?>
                                                            <!-- itemRenderers\component\myComponents\RendererDGImageSelect.mxml -->
                                                            <mx:HBox xmlns:mx=" http://www.adobe.com/2006/mxml"
                                                            horizontalAlign="center">

                                                            <mx:Script><![CDATA[
                                                            import mx.events.FlexEvent;

                                                            private var _classImgSrc:Class;
                                                            private var _sLabel:String;

                                                            override public function set data(value:Object):void {
                                                            if(value != null) {
                                                            super.data = value;
                                                            _classImgSrc = value.icon; //set local variables
                                                            _sLabel = value.label
                                                            invalidateProperties(); //causes "commitProperties" to be called later
                                                            }
                                                            // Dispatch the dataChange event.
                                                            dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
                                                            }

                                                            override protected function commitProperties():void
                                                            {
                                                            super.commitProperties();
                                                            onSale.source = _classImgSrc; //actually set the values
                                                            testLabel.text = _sLabel;
                                                            }//
                                                            ]]></mx:Script>

                                                            <mx:Image id="onSale" height="20"/>
                                                            <mx:Label id="testLabel"></mx:Label>
                                                            </mx:HBox>
                                                            • 27. Re: Datagrid scroll bug??
                                                              esterojas Level 1
                                                              Don't let anyone tell you aren't completely awesome! Because you are! Thank you so much for helping on this. I don't think I would have figured this out for quite some time without your help (if ever). I changed my code based on the help you gave and it worked great. The only issue I am having now is that I am using dynamic images (url) and not embedded ones so it has to load the image in..little lag. I probably will try to create some sort of loading holder if possible to give the user some feedback instead of just a blank space where the image should be. Other than that..everything is perfect!

                                                              Thanks so much for all your help!
                                                              Jas
                                                              • 28. Re: Datagrid scroll bug??
                                                                PitySOFT Level 1
                                                                Thanks a lot guys!

                                                                I just ha same problem with a datagrid ... and I'm sure that will took a lot of time to figure this out! Hope more people find the solution here.