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 

Context sensitive columns not only for FocusRow

 
Post new topic   Reply to topic    Infralution Support Forum Index -> Virtual Tree Feature Requests
View previous topic :: View next topic  
Author Message
MHB



Joined: 04 Apr 2005
Posts: 69

PostPosted: Tue Jul 26, 2005 5:17 pm    Post subject: Context sensitive columns not only for FocusRow Reply with quote

I didn't realize that context sensitive columns only worked on the FocusRow until I tried it. This really doesn't seem very logical. I expected a context sensitive column to be shown whenever a visible row (not just the FocusRow) supported the given column. Would it be possible to get this behaviour, perhaps configurable?

I've implemented the behaviour myself by overriding ColumnInContext and looping through the rows from toprowindex to bottomrowindex and doing a costum check, but for some reason it doesn't work perfectly. When the tree is first shown, the context sensitive column is not displayed until I resize the tree window or expand a node, even though ColumnInContext returns true from the beginning.
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Tue Jul 26, 2005 11:30 pm    Post subject: Reply with quote

The reason it is not designed the way you suggest is that you would tend to end up with an unworkably large number of columns displayed once you start expanding items. However you can make it this way if you would prefer that.

Try the following code:

Code:

class CustomVT : Infralution.Controls.VirtualTree.VirtualTree
{
    protected override bool ColumnInContext(Column column)
    {
        Hashtable rows = new Hashtable();
        GetRows(TopRowIndex, BottomRowIndex, rows);
        for (int i=TopRowIndex; i <= BottomRowIndex; i++)
        {
            Row row = (Row)rows[i];
            RowBinding binding = GetBindingForRow(row);
            if (binding != null)
            {
                if (binding.SupportsColumn(column))
                    return true;
            }
        }
        return false;
    }

    protected override void OnLayout(System.Windows.Forms.LayoutEventArgs levent)
    {
        this.UpdateColumnsContext();
        base.OnLayout (levent);
    }
}


Currently the tree only calls the UpdateColumnsContext method when the focus is changed - which is probably why you couldn't get it to work. By forcing this to be called each time OnLayout is called you get the desired behaviour. We will change this in the next release so that UpdataColumnsContext is called from OnLayout by default.
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
MHB



Joined: 04 Apr 2005
Posts: 69

PostPosted: Wed Jul 27, 2005 9:59 am    Post subject: Reply with quote

Infralution wrote:
The reason it is not designed the way you suggest is that you would tend to end up with an unworkably large number of columns displayed once you start expanding items. However you can make it this way if you would prefer that.


I'm only talking about the visible rows, not all expanded rows. At least in my case, most of the time this wouldn't result in too many columns. Otherwise, one could change the behaviour accordingly...

The reason I'm not satisfied using my own implementation is that you could implement a better solution by taking advantage of the fact that you are notified when rows enter and leave the view. Columns can only be added when rows enter the view, and removed when rows leave the view. I have to loop through every visible row each time ColumnInContext is called, just like you exemplified. And I can't really guess how often that is...

Infralution wrote:
Code:

protected override void OnLayout(System.Windows.Forms.LayoutEventArgs levent)
{
    this.UpdateColumnsContext();
    base.OnLayout (levent);
}


Thanks for the suggestion, but this doesn't seem to make any difference! Still, the column is not shown until I expand an item or resize the window. Not even selecting an item that supports the column is enough.
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Wed Jul 27, 2005 10:51 am    Post subject: Reply with quote

I understand you were only talking about visible rows - however if you have a number of different row types which each have a number of independent columns then you can quickly end up with a huge number of columns displayed if you expand a few items.

We actually implemented the code I posted by modifying the Dataset Browser Sample. It works fine - although it does illustrate the problem I mentioned above of managing large numbers of columns.

If we were to add this as an option in VirtualTree we would have to implement it in pretty much the same way as I posted here - as there is no internal notification of new rows being displayed. As it turns out this seems to perform OK anyway. Obviously however it is not as efficient as the default algorithm which just checks the current FocusRow.

I'm not sure why you were unable to get it to work. I will email you a copy of the modified DataSet Browser sample to play with.
_________________
Infralution Support


Last edited by Infralution on Wed Jul 27, 2005 10:43 pm; edited 1 time in total
Back to top
View user's profile Send private message Visit poster's website
MHB



Joined: 04 Apr 2005
Posts: 69

PostPosted: Wed Jul 27, 2005 3:34 pm    Post subject: Reply with quote

Infralution wrote:
If we were to add this as an option in VirtualTree we would have to implement it in pretty much the same way as I posted here - as there is no internal notification of new rows being displayed. As it turns out this seems to perform OK anyway. Obviously however it is not as efficient as the default algorithm which just checks the current FocusRow.

Ok, of course it was my assumption there was an internal notification. How else would you update the TopRowIndex, for instance?

Infralution wrote:
I'm not sure why you were unable to get it to work. I will email you a copy of the modified DataSet Browser sample to play with.

Thanks. I can see it works under those circumstances. I also modified the filebrowser sample to verify that it works using object binding. However, I still sometimes get the problem with my own project. I'll try to narrow it down and make a sample project... Trouble is, my project is getting rather complicated due to the very dynamic nature of the data source!
Back to top
View user's profile Send private message
MHB



Joined: 04 Apr 2005
Posts: 69

PostPosted: Wed Jul 27, 2005 3:47 pm    Post subject: Reply with quote

It seems the problem may have been not ending ColumnInContext() by calling base.ColumnInContext()! Apparently it works when I do that, even though base.ColumnInContext() never returns true. This is because I'm using some level of programmatic data binding.
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Wed Jul 27, 2005 10:42 pm    Post subject: Reply with quote

MHB wrote:
Ok, of course it was my assumption there was an internal notification. How else would you update the TopRowIndex, for instance?


Well obviously we know when the TopRowIndex changes - but there are a whole range of other possible causes for new rows to be displayed or previously displayed rows to disappear. For instance:

a. User resizes the window causing more or less items to be displayed
b. User expands or collapses a node
c. Items are added or removed from data bound collections

For this reason we don't calculate upfront what new rows are to be added and which removed - we just calculate in OnLayout what rows should be visible given the current state.
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
MHB



Joined: 04 Apr 2005
Posts: 69

PostPosted: Thu Oct 06, 2005 4:35 pm    Post subject: Reply with quote

I'm revisiting this subject because I'm having trouble getting something like the above ColumnInContext example to work right. Don't know whether this has been introduced in a recent version... I'm at 2.1.0 now and only just discovered the issue.

Problem is, when ColumnInContext gets called on expanding a row, the rows are not updated yet, and BottomRowIndex reflects the tree before the row is expanded. It's like ColumnInContext gets called a bit early... When collapsing a row, BottomRowIndex seems correct.
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Thu Oct 06, 2005 11:11 pm    Post subject: Reply with quote

I've just modified the Dataset Browser sample to use the code discussed earlier in this thread by adding the following:

Code:

public class MyTree : VirtualTree
{
    protected override bool ColumnInContext(Column column)
    {
        Hashtable rows = new Hashtable();
        GetRows(TopRowIndex, BottomRowIndex, rows);
        for (int i=TopRowIndex; i <= BottomRowIndex; i++)
        {
            Row row = (Row)rows[i];
            RowBinding binding = GetBindingForRow(row);
            if (binding != null)
            {
                if (binding.SupportsColumn(column))
                    return true;
            }
        }
        return false;
    }
}


And then changed the designer generated code to use the derived MyTree class. Note that you don't need to override OnLayout anymore because UpdateColumnContext is called by the base method now.

This all works without any problems with the latest version - Maybe try this on your machine. Note that BottomRowIndex is the index of the last displayed row. If you haven't moved the top row (by scrolling) and the size of the window is unchanged then the BottomRowIndex shouldn't change. So the code above only considers displays columns that are in context for the currently displayed rows. If you wanted it to be for all rows then you could change BottomRowIndex to LastRowIndex and TopRowIndex to FirstRowIndex - although this will be much more expensive.
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
MHB



Joined: 04 Apr 2005
Posts: 69

PostPosted: Fri Oct 07, 2005 10:26 am    Post subject: Reply with quote

I can see that the problem is not exposed by this example, probably because there are a lot of rows in the data source. The problem only seems to occur when the rows of the tree do not cover the entire display area, and an expanded row introduces more rows (and hence BottomRowIndex should be increased), and one of these is the only one supporting some column. I will mail you a sample project exhibiting this behaviour.
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Mon Oct 10, 2005 12:44 am    Post subject: Reply with quote

Thanks for the sample project. The problem is a "chicken and egg" type thing. When we introduced variable and auto height rows we needed to change the algorithm to calculate the NumVisibleRows property to take into account individual row heights - so that the vertical scrollbar is correct. This is done in OnLayout after the Widgets for each of the rows have been created. So after OnLayout is called NumVisibleRows is correct and so therefore is BottomRowIndex (which depends on this).

The problem is that ColumnInContext (which you are overriding) is called at the beginning of OnLayout and so NumVisibleRows has not yet been recalculated. ColumnInContext has to be called at the beginning of OnLayout because the layout of widgets depends on which columns are currently in context.

The solution is to calculate the bottom row index yourself based on the minimum row height. eg

Code:

int numVisibleRows = DisplayHeight / MinRowHeight;
int topIndex = TopRowIndex;
int bottomIndex = Math.Min(LastRowIndex, topIndex + numVisibleRows - 1);


This will calculate the maximum number of rows that could possibly be visible - which will in most cases be an overestimate - so you may potentially be showing columns for rows that are not yet visible - but in practice I don't think this is likely to be an issue.
_________________
Infralution Support
Back to top
View user's profile Send private message Visit poster's website
MHB



Joined: 04 Apr 2005
Posts: 69

PostPosted: Tue Oct 11, 2005 2:11 pm    Post subject: Reply with quote

Nice explanation Smile

I can't think of a simple better solution either, so I'll stick to the overestimation for the time being, and hope nobody experiences it as a problem. Looks like my demands are approaching the limit of VirtualTree Sad

In theory, shouldn't it be possible to solve this? Perhaps by getting rid of the high level ColumnInContext() that works on all rows at the same time, and instead dynamically determine the supported columns for each row/widget as they are created, generating a list of columns in context in the process? Of course, this will depend on exactly how the widgets are set up, and whether it's possible to add (unsupported) columns to a widget along the way...
Back to top
View user's profile Send private message
Infralution



Joined: 28 Feb 2005
Posts: 5027

PostPosted: Tue Oct 11, 2005 10:16 pm    Post subject: Reply with quote

The problem is that the Active "InContext" columns can affect the height of the rows displayed (if AutoFitHeight is true) and thus the number of visible rows. So you have to do this before calculating the NumVisibleRows - but your algorithm for calculating the displayed rows depends on the NumVisibleRows.

The only way you could handle this rigourously would be to override OnLayout and call the base.OnLayout in a loop until the NumVisibleRows does not change - but this seems like overkill and would have an adverse affect on performance.
_________________
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 Feature Requests All times are GMT
Page 1 of 1

 
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