Terminal.Gui
Terminal.Gui copied to clipboard
Add 'Visible' property to ColumnStyle in TableView
This is a new ticket to come out of https://github.com/migueldeicaza/gui.cs/issues/1463 (I've created a new ticket since that one is closed and was more general).
It is to add the ability to hide columns in TableView:
I think a better solution would be to add a Visible property to the ColumnStyle class. I can look into this, it should be reasonably easy.
I have taken a look at this. Its pretty hard and would increase complexity in the following areas:
- A lot of operations e.g.
EnsureSelectedCellIsVisible
andEnsureValidScrollOffsets
queryTable.Columns
directly. Making these consider hidden columns would increase code complexity - Fields like
ColumnOffset
andSelectedColumn
areint
fields with public setters. Quite a bit of complexity there (e.g. are hidden columns scrollable/selectable?). What doesSelectedColumn++
do when the next col is hidden (does it stay the same or skip the hidden ones?) This could make users existingfor
loops unpredictable. -
TableSelection
(multi cell selections) describes a rectangle selected in the view. Allowing hidden columns could easily result in area selections including hidden cells.
I looked into how users can work with the current implementation of TableView
and still get column show/hide. It can be done by combining void Remove(DataColumn col)
and DataTable Copy()
. Although this is not ideal it would be a route people could go down until (if) this feature is implemented:
[Fact]
public void TableView_RemoveCol_ThenReAdd ()
{
var tv = SetUpMiniTable ();
tv.Style.ExpandLastColumn = true;
tv.Style.InvertSelectedCellFirstCharacter = true;
// width exactly matches the max col widths
tv.Bounds = new Rect (0, 0, 5, 4);
tv.Redraw (tv.Bounds);
string expected = @"
┌─┬─┐
│A│B│
├─┼─┤
│1│2│
";
GraphViewTests.AssertDriverContentsAre (expected, output);
// Take a copy of the original table because Remove will delete row data along with the column
var orig = tv.Table.Copy ();
// 'hide' a column
var colB = tv.Table.Columns [1];
tv.Table.Columns.Remove (colB);
tv.Redraw (tv.Bounds);
expected = @"
┌───┐
│A │
├───┤
│1 │
";
GraphViewTests.AssertDriverContentsAre (expected, output);
// Column cannot just be re-added. Since row data will be null if you do that. Instead we have to
// go back to the original table.
tv.Table = orig;
tv.Redraw (tv.Bounds);
expected = @"
┌─┬─┐
│A│B│
├─┼─┤
│1│2│
";
GraphViewTests.AssertDriverContentsAre (expected, output);
// Shutdown must be called to safely clean up Application if Init has been called
Application.Shutdown ();
}
A wrapper to get the ColumnStyle
length based on a property IsHidden
. If is true, then will return 0
and won't be redrawn. But as you said this will would increase code complexity.
A wrapper to get the
ColumnStyle
length based on a propertyIsHidden
. If is true, then will return0
and won't be redrawn. But as you said this will would increase code complexity.
Not drawing the column is relatively easy but navigation (left/right arrow keys etc) is where it gets complicated and that is before you get to square selections (shift right etc)...
I know what you meaning :-) An more easy workaround is do like you did but removing and re-adding within a controlled way. Maybe create a class to store the hidden columns after removing. You will need to add some more information about the position, etc., for when the column will be unhidden to recreate in the original positions.
Hello,
for anyone looking for a workaround here is what worked for me:
I used SQL to query data and then load it from datatable to tableview. Then using ColumnStyle I set MaxWidth to 0. The only difference is a double border at the end which is not a big deal - the border does not stack so if you have more hidden columns at the end there will be still one additional border (well at least for 2 hidden columns, have not tried it with more).
Also here is the code used to apply ColumnStyles:
tableView.Style.ColumnStyles.Add(tableView.Table.Columns["colname"], new TableView.ColumnStyle() { MaxWidth = 0 });
The user can still select it but it shouldn't be a big problem...
@tznind how about not draw if width is equal to zero?
Thanks for sharing this trick @radek3911, very handy.
I see you are using Add
and the ColumnStyle
constructor. Another option which you might find tidier or more readable is to use GetOrCreateColumnStyle
directly (both work fine though).
tableView.Style.GetOrCreateColumnStyle (tableView.Table.Columns ["colname"]);
colStyle.MaxWidth = 0;
@tznind how about not draw if width is equal to zero?
That would be a good idea. Once Visible
is added we could do something like:
private bool _visible = true;
public bool Visible
{
get { return MaxWidth > 0 && _visible; }
set { _visible = value; }
}
Proposed new code in ColumnStyle
The ability to hide columns is definetly a nice feature to have.
It has some complexity because keyboard navigation and mouse selection etc have to all consider invisible columns. So for example when you press right from A1 and column B is invisible the cursor needs to move to C1. So its not just a rendering issue.
I have been meaning to find time to dive deeper into a solution for this feature but I have also just started a new job so don't have as much time at the moment to tackle it.
Ok I've started tinkering on this https://github.com/gui-cs/Terminal.Gui/pull/2243 I have added as many TODO items as I can think of but there will probably be more as I dig into this feature.