Eto TableRow ScaleHeight / TableLayout Scaling

Hello Everyone,

I would like to be able to control the height scaling of an Eto.Forms TableLayout TableRow. I have a TableLayout with 2 rows and 1 column, first row being the “header”, second row being the “content”. Header row has a height smaller than the content row, however when both are displayed, the header row scales to the height of the content row.

I realize that what I am describing is an Eto.Forms.Expander, which does not have this problem, but there is no way for me to remove the horizontal header line in it, without using WPF styling, so the solution was to mimic the behaviour using TableLayout.

The Eto.Forms.TableRow ScaleHeight property is not doing anything in this regard. Below is a mockup code for what I am trying to achieve:


 protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            Dialog ptTestDialog = new Dialog();
            ptTestDialog.MinimumSize = new Eto.Drawing.Size(280, 320);
            ptTestDialog.Width = 320;
            ptTestDialog.Height = 450;
            ptTestDialog.Resizable = true;
            ptTestDialog.BackgroundColor = Eto.Drawing.Colors.White;
            ptTestDialog.Padding = 2;

            bool expanded = false;
            int height = 24;
            Button headerButton = new Button();

            TableLayout header = new TableLayout(2, 1);
            header.Add(new Label() { Text = "headerLabel" }, new Eto.Drawing.Point(0, 0));
            header.Add(headerButton, new Eto.Drawing.Point(1, 0));
            header.SetColumnScale(0, true);
            header.SetColumnScale(1, true);
            header.SetRowScale(0, true);
            header.Height = height;

            List<string> datastore = new List<string>() { "test1", "test2", "test3" };
            Eto.Forms.ListBox listBox = new Eto.Forms.ListBox();
            listBox.DataStore = datastore;
            listBox.Height = height * 3;

            TableLayout tableLayout = new TableLayout(1,2);
            tableLayout.Add(header, new Eto.Drawing.Point(0, 0));
            tableLayout.Add(null, new Eto.Drawing.Point(0, 1));
            tableLayout.SetColumnScale(0, true);
            tableLayout.SetRowScale(0, true);
            tableLayout.SetRowScale(1, false);
            tableLayout.Rows.ToList()[0].ScaleHeight = false;

            headerButton.Click += (o, e) => {
                if (expanded)
                {
                    expanded = false;
                    tableLayout.Add(null, new Eto.Drawing.Point(0, 1));
                    tableLayout.SetRowScale(1, false);
                }
                else
                {
                    expanded = true;
                    tableLayout.Add(listBox, new Eto.Drawing.Point(0, 1));
                    tableLayout.SetRowScale(1, true);
                }            
            };

            StackLayout stack = new StackLayout();
            stack.HorizontalContentAlignment = HorizontalAlignment.Stretch;
            stack.Orientation = Orientation.Vertical;
            stack.Items.Add(tableLayout);
            stack.Items.Add(null);

            ptTestDialog.Content = stack;
            ptTestDialog.ShowModal();

            return Result.Success;
        }

which results in the following screenshots:


Any suggestions would be appreciated. StackLayout solves this, but does not work with modifying the layout content at runtime.

All the best,
Radu

Any reason why you don’t opt for DynamicLayout?
the scaling in DynamicLayout is way simpler.

Because DynamicLayout can’t be modified at runtime, unlike TableLayout.

You can try another approach using a combination of a StackLayout and TableLayout.
Something along the lines of

protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
    Dialog ptTestDialog = new Dialog();
    ptTestDialog.MinimumSize = new Eto.Drawing.Size(280, 320);
    ptTestDialog.Width = 320;
    ptTestDialog.Height = 450;
    ptTestDialog.Resizable = true;
    ptTestDialog.BackgroundColor = Eto.Drawing.Colors.White;
    ptTestDialog.Padding = 2;

    bool expanded = false;
    int height = 24;
    Button headerButton = new Button();

    StackLayout header = new StackLayout();
    header.Orientation = Orientation.Horizontal;
    header.Items.Add(new Label() { Text = "headerLabel" });
    header.Items.Add(headerButton);
    header.Height = height;

    List<string> datastore = new List<string>() { "test1", "test2", "test3" };
    Eto.Forms.ListBox listBox = new Eto.Forms.ListBox();
    listBox.DataStore = datastore;
    listBox.Height = height * 3;

    TableLayout tableLayout = new TableLayout(1, 2);
    tableLayout.Add(header, new Eto.Drawing.Point(0, 0));
    tableLayout.Add(whatever, new Eto.Drawing.Point(0, 1));
    tableLayout.SetColumnScale(0, true);
    tableLayout.SetRowScale(0, false);
    tableLayout.SetRowScale(1, true);

    headerButton.Click += (o, e) => {
        if (expanded)
        {
            expanded = false;
            tableLayout.Remove(tableLayout[0, 1]);
            tableLayout.Add(whatever, new Eto.Drawing.Point(0, 1));
            tableLayout.SetRowScale(1, false);
        }
        else
        {
            expanded = true;
            tableLayout.Remove(tableLayout[0, 1]);
            tableLayout.Add(listBox, new Eto.Drawing.Point(0, 1));
            tableLayout.SetRowScale(1, true);
        }
    };

    StackLayout stack = new StackLayout();
    stack.HorizontalContentAlignment = HorizontalAlignment.Stretch;
    stack.Orientation = Orientation.Vertical;
    stack.Items.Add(tableLayout);
    stack.Items.Add(whatever);

    ptTestDialog.Content = stack;
    ptTestDialog.ShowModal();

    return Result.Success;
}

You can try using a StackLayout for the header and a TableLayout for the overall layout. This combination allows you to control the row height scaling while still being able to modify the layout at runtime. The header row should now have a fixed height, and the content row should resize accordingly.