Infralution Support Forum Index Infralution Support
Support groups for Infralution products
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

GetCellData
Goto page 1, 2  Next
 
Post new topic   Reply to topic    Infralution Support Forum Index -> Virtual Tree Support
View previous topic :: View next topic  
Author Message
Shailendra Baghel



Joined: 25 Nov 2005
Posts: 23

PostPosted: Fri Jan 20, 2006 1:37 pm    Post subject: GetCellData Reply with quote

Hi,

I have a context menu and on right click of it i want to add a value of a column.

In the context menu's event handler i am calling
_tree.PerformLayout();
_tree.Update();

Why does not the Grid's GetCellData() event gets fired for all the rows in viewable space.

Basically my aim is to set some value in a column when context menu's event is fired. So for this, the GetCellData() should be fired again after i have clicked on the context menu.

How can the above be acheived?
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Mon Jan 23, 2006 4:30 am    Post subject: Reply with quote

Try _tree.UpdateData() instead.
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
Shailendra Baghel



Joined: 25 Nov 2005
Posts: 23

PostPosted: Wed Jan 25, 2006 11:35 am    Post subject: VisibleRows Reply with quote

Thanks for the reply.

When grid comes up for the first time, UpdateVisibleRows() gets called up

private void UpdateVisibleRows()
{

_visibleRows.Clear();

// Check if the root row has been created
//
if (_rootRow != null)
{
int topIndex = TopRowIndex;
int bottomIndex = Math.Min(topIndex + MaxVisibleRows, LastRowIndex);
GetRows(topIndex, bottomIndex, _visibleRows);
}
}

Now the Grid cache has stored rows from topIndex till bottomIndex. Lets assume these have the following values

GridIndex -> 0 <- topIndex
GridIndex -> 1 <- topIndex
GridIndex -> 2 <- topIndex
GridIndex -> 3 <- topIndex
GridIndex -> 4 <- topIndex
.......
GridIndex -> 43 <- bottomIndex

In the viewable space i can see only rows from 0 to 20
GridIndex ->0
....
GridIndex -> 19

Now i hit the lower arrow of the vertical scroll bar,
GetCellData() routine gets called and the grid asks for data for GridIndex=44.

In my application i am also doing a caching in DataSource class which derives from IList.

What I need is that whenever a event happens ( like KeyDown,KeyUp,PageDown,PageUp ) and OnPaint gets called ,I need that the Grid should ask me data starting from the TopMost Visible Row to BottomMost visible row i.e for the range of rows in the viewable space only irrespective of what is stored in the following

private SortedList _childRows = new SortedList(); // Row class.

Currently this is not happening and the grid asks me for the data which is not in its cache.

How to acheive the above?
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Thu Jan 26, 2006 6:56 am    Post subject: Reply with quote

UpdateVisibleRows creates and caches Row objects to represent all the objects that could potentially be displayed. Since row heights can vary individually this is done by calculating the maximum number of displayed rows based on the minimum row height. This is why you see rows 1 to 43 being created and cached although only rows 1 to 19 are visible. If you set the MinRowHeight to equal RowHeight then these will match up.
When you scroll the tree it only creates row objects (and requests RowData) that have not already been created.

Note that all layout of row widgets and requesting of data is done from within the OnLayout method. Methods which change the scrolling set the TopIndex which in turn calls PerformLayout. This allows SuspendLayout and ResumeLayout methods to be used to minimize the number of times that layout (which is reasonably expensive) is performed.

It still sounds like you are trying to reinvent the Virtual Tree scrolling mechanism to handle the case where you don't know the number of items in your datasource as per your previous thread (http://www.infralution.com/phpBB2/viewtopic.php?t=269). As I suggested then I believe it would be much better to modify your datasource as suggested:

Quote:
Because Virtual Tree uses the DataSource IList.Count property to size the vertical scrollbar you really have to return the correct value from IList.Count. If you at first you only have an estimate for the true value then you could return that and change it when you really do know the actual value. To notify VirtualTree you should implement the IBindingList interface and raise the ListChanged event when you change the Count property. It would generally be better to increase the Count (ie underestimate it initially) so that it appears to the user as if new items are added rather then starting with (apparently) a very large number of items and then having them seemly disappear when the count is reduced.

_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
Shailendra Baghel



Joined: 25 Nov 2005
Posts: 23

PostPosted: Mon Jan 30, 2006 12:37 pm    Post subject: Reply with quote

Thanks for the reply.

I got your suggestion but for my requirment i cannot do that.
Its good that grid is caching but what i need is that it shoud never cache data within itself.
It should remember what rows have been expanded and what are not but whenever OnLayout() gets called it should ask from the
DataSource data from the topmost visible row and onwards.

Can you provide some pointers for above as i am stuck?
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Tue Jan 31, 2006 8:45 am    Post subject: Reply with quote

The caching mechanism is integral to the design of Virtual Tree. Changing the way this works would be a very large task. You can force Virtual Tree to release cached rows by calling UpdateRows (note that you generally can't call this from methods that are in turn called from Virtual Tree eg OnLayout)

If you have a data source that contains very large objects or the objects themselves hold valuable system resources then you should probably consider implementing a data source that holds proxies to the underlying data objects as we suggested in an earlier email.
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
Shailendra Baghel



Joined: 25 Nov 2005
Posts: 23

PostPosted: Wed Feb 01, 2006 11:27 am    Post subject: Reply with quote

I understand that the caching mechanism is integral to the design of virtual tree and it's excellent but how do i solve my problem?

My overall objective is that the data i have in my datasource is in the form of a linked list and each node has no property with indicates that the data for this node will shown at a particular index in the grid.

All i have is a reference to the topNode in that list. This topNode is adjsted accordingly to the events occurred. For example when user hits the "Down" arrow key or if the user hits the lower triangle in vertical scroll bar, the next node to topNode becomes the topNode.

This topNode should correspond to the data for the topmost visible row in the viewing space.

Now the grid asks the datasource in terms of index. What node should i correspond to this index? This is a bottleneck i am facing.

One solution is that whenever an event like ( pagedown, pageup, keyDown, keyUp ), i adjust the topNode in the dataSource. Whenever GetCellData() is called for the first time after an event occured the index i should recieve is an index which correspond to the topMost visible row in the viewing space. The index after that will correspond to nodes which occur after the topNode.

Did you understand the problem? If yes any pointers to solve it.
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Wed Feb 01, 2006 10:36 pm    Post subject: Reply with quote

I think I understand the problem. I also think that attempting to modify Virtual Tree source code to cope with this sort of data source is the wrong way to go about addressing the problem. Virtual Tree is built from the ground up on the basis that the datasource objects support the IList interface (which provides numeric indexing of elements). It is not possible to build a control which supports virtual loading of elements (ie only loading those items actually required for display) without this. To change this would be to completely rewrite the code.

Having said that I think that you can still use virtual tree to display your linked list data source. The simplest approach would be to copy the elements of your data source to a collection that does support IList (such as an ArrayList) and set this as your data source. However I assume from your previous posts that your data source is very large (>10000 elements?) and so this isn't a viable solution.

The second approach is to write a proxy data source class that implements the required IList interface but underneath actually retrieves data from your linked list data source. As it actually retrieves data the proxy stores it internally in an ArrayList or Hashtable so that future requests to retrieve the item at a given index can be made much more quickly. If you don't know the actual number of items in the linked list then you will have to take the approach suggested before of returning an estimate for IList.Count property and using the IBindingList interface to notify VirtualTree if when you need to change this estimate.

For instance you might load the first 30 elements from the linked list when the proxy is first created and set the estimated count to 31. If the virtual tree then requests element 31 (by calling IList.Item(31)) you would then load the next 30 elements and update the estimated count to 61 and call the IBindingList.ListChanged event to notify the tree that the list had changed.

Note that with this type of approach there is no real way to scroll to the end of the data source list since scrolling to the end will typically cause more data to be loaded by the proxy and the Count (and hence the scrollbar) to be updated. But this limitation is really intrinsic in the type of data source (linked-list) that you have chosen. If you need more assistance with this approach we could provide it on a consultancy basis.

A final approach you could consider is to change your user interface to a style that reflects the reality of your underlying data source. That is, adopt a user interface similar to Googles search result page where only a fixed number of items are actually displayed in the control at one time and the user must use next/previous buttons to load a new set of items into the control. To do this you would simply keep track of your current position within the linked list and then load the next (or previous) 20 items into an array list and set this as your datasource. This would actually be considerable simpler to implement then the second approach and it would also probably be easier for your end users. It also has the advantage that only items cached are those currently displayed.
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
Shailendra Baghel



Joined: 25 Nov 2005
Posts: 23

PostPosted: Thu Feb 02, 2006 12:36 pm    Post subject: Reply with quote

Thanks for giving time to understand the problem.

Well i had to add the following to the requirments list.

1. The data to be displayed on the viewer component is huge.
2. The complete data connot be retrieved in one shot from the lower layers of the application. These layers can supply data only in buckets.

In the dataSource i have to cache the above data and not hold the complete data for lifetime.

You suggested 3 approaches.

1. The first approach asks me to completely build my linked list with all the data in one shot and copy that data in ArrayList and give this dataSource to grid. As i said above i cannot get the whole data in one shot and also if i could get, it would be time consuming.

2. The second approach asks me to build my linked list as i get data from lower layers and maintain it. Well this is difficult as i have to keep track as to where i need to add nodes in linked list as the user can jump to any location. And every time i add something to linked list i have to raise the ListChanged Event. Here my dataSource would continue to grow as user is browsing the grid.

3. The third approach can only solve the problem. But as you suggest this cant be acheived with Infralution. This gets more difficult as our "project management people" come into picture and we have already spent a good amount of time with Infralution.
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Thu Feb 02, 2006 9:21 pm    Post subject: Reply with quote

Quote:
The second approach asks me to build my linked list as i get data from lower layers and maintain it. Well this is difficult as i have to keep track as to where i need to add nodes in linked list as the user can jump to any location.

Actually it isn't that difficult - you simply keep a link to the next item you will load and the index of that item (which is your estimated count). All the other items the items you have previously loaded are kept in an ArrayList so that you can retrieve them easily by index.

Quote:
And every time i add something to linked list i have to raise the ListChanged Event. Here my dataSource would continue to grow as user is browsing the grid.

Yes with this solution your data source will continue to grow - but since this is only at the rate that a user can page through data it will be very slow (relative at least to the speed at which the computer could load data). I think it is very unlikely that you users will have the patience to manually scroll through huge amounts of data especially given that they can really only get the next page of data anyway. If they do need to scroll rapidly through the entire data set then you have chosen the wrong underlying data source implementation - because this simply isn't possible with a linked list approach.

Quote:
The third approach can only solve the problem. But as you suggest this can't be acheived with Infralution. This gets more difficult as our "project management people" come into picture and we have already spent a good amount of time with Infralution.

You would still use Virtual Tree to display the data - however you would manage loading the page of data and setting the data source when the user presses "Next", "Previous". The vertical scrollbar is really only an good user interface paradigm when you actually know how many items are in the list and you can truly give random acess to elements within the list. I don't think that you will find another control on the market that does what you want. Other controls that support virtual loading do it either by requiring index based access to items (as we do) or by loading pages incrementally (as in the second approach).
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
Shailendra Baghel



Joined: 25 Nov 2005
Posts: 23

PostPosted: Mon Feb 20, 2006 5:34 am    Post subject: Reply with quote

Hi,

To continue with the discussion,i am following the "third" approach and the parent level data ( Level=1) is coming fine. There is some problem faced while we expand a Row class.

For example.

Row1(Level1) (Item1)
Row2(Level1) (Item2)
Row3(Level1) (Item3)
.
.
.
.RowN(Level1) (ItemN)

Here Item is the "domain" of the Row class.

Now i expand Row2

Row1(Level1) (Item1)
Row2(Level1) (Item2)
Row21(Level2) (Item21)
Row22(Level2) (Item22)
Row23(Level2) (Item23)
Row3(Level1) (Item3)
.
.
.
.RowN(Level1) (ItemN)


Now i hit the KeyDown "Key" and the Row and associated Item objects should be like the following

Row1(Level1) (Item2)
Row11(Level2) (Item21)
Row12(Level2) (Item22)
Row13(Level2) (Item23)
Row2(Level1) (Item3)
Row3(Level1) (Item4)
.
.
.
.RowN(Level1) (ItemN)

The objective is to detach the child list from any row and attach it to another row. As in the above example ChildList (Item21,Item22,Item23) is to be detached from Row2 and associated to Row1.
I hope you have got my problem. Any pointers how to progress?

As already stated in previous discussion i tell the grid that i have only i page of data and on Events (KeyDown,KetUp.. ) i am just doing UpdateRowData() to change the value of cells. When we collpase a Row , the Row class internally stores the ChildList which in my case should not.

Any demo code wiill be helpful.
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Tue Feb 21, 2006 9:00 am    Post subject: Reply with quote

If you were doing the third approach I suggested then I would have expected that you would have a page down button and in the event handler you would load a new array list of items from your data source then you would set virtualtree.DataSource to this new list. Something like:


Code:
ArrayList currentItems = new ArrayList();
for (int i=0; i < myPageSize; i++)
{
    object item = MyDataSource.GetNextItem();
    if (item != null)
        currentItems .Add(item)
}
_virtualTree.DataSource = currentItems;


It seems like maybe you are trying to keep the same array of items and just update their content and call UpdateRowData to reflect the change. This would seem likely to lead to more issues. It might be possible to do it this way but you would almost certainly have to call UpdateRows() rather than UpdateRowData() or you will definitely have issues with the children of rows not being updated.
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
Shailendra Baghel



Joined: 25 Nov 2005
Posts: 23

PostPosted: Tue Feb 21, 2006 9:49 am    Post subject: Reply with quote

Thanks,

Infact i am calling UpdateRowData() and i think this is leading to problems as you suggested.

As you explained i have a ArrayList which stores the actual data and i call UpdateRowData()

Also i have handled the following to set the correct value in Item.

protected override RowData GetDataForRow(Row row)
{
// Reset the correct data
//
TreeRow objRow = (TreeRow)row.Item;

// get correct values from ArrayList based on displacement from TopRow.
ReSetData(ref objRow, row.RowIndex-this.TopRowIndex);

// Call base.
//
return base.GetDataForRow (row);
}


with the above approach i am facing the following problem of expanded rows when i call UpdateRowData()

Row1(Level1) (Item1)
Row2(Level1) (Item2) // This is expanded.
Row21(Level2) (Item21)
Row3(Level1) (Item3)
.
.
RowN(Level1) (ItemN)

No i hit the KeyDown and i call UpdateRowData() and the following happens

Row1(Level1) (Item2)
Row2(Level1) (Item3) // This is expanded.
Row21(Level2) (Item31)
Row3(Level1) (Item4)
.
.
RowN(Level1) (ItemN)

So always the row at the index 2 is expanded when i continue to do KeyDown but the Item of that Row has changed as i have changed the Data for Row.

I hope you could understand the problem.

But I think by calling UpdateRows() the same behaviour will be seen?
The expansion logic should see the "Item" of a row and not the index of a row.
Back to top
View user's profile Send private message
Shailendra Baghel



Joined: 25 Nov 2005
Posts: 23

PostPosted: Tue Feb 21, 2006 11:42 am    Post subject: Reply with quote

You suggsted the following solution

ArrayList currentItems = new ArrayList();
for (int i=0; i < myPageSize; i++)
{
object item = MyDataSource.GetNextItem();
if (item != null)
currentItems .Add(item)
}
_virtualTree.DataSource = currentItems;

Can i specify parent-child relationship within the above ArrayList and when i set the DataSource to Virtual Tree that relationship gets visible in the tree?

If i set a property "Expanded" in object "item" to true, then the item objects following that are shown as childs of that item.

Can something like above be achieved? If yes some psuedo-code will be helpful.
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Tue Feb 21, 2006 11:24 pm    Post subject: Reply with quote

Quote:
Can i specify parent-child relationship within the above ArrayList and when i set the DataSource to Virtual Tree that relationship gets visible in the tree?


No any items you put in the array list will be displayed as first level nodes. To specify the children for an item you handle the GetChildren event (or override the GetChildrenForRow method). Something like:

Code:

protected override IList GetChildrenForRow(Row row)
{
     if (row.Item is MyDataItem)
    {
        MyDataItem item = row.Item as MyDataItem;
        return MyDataSource.GetChildren(item);
    }
    return null;
}


ie you will need to have some way of returning a list of items which are children of a given item.
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Infralution Support Forum Index -> Virtual Tree Support All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group